ステートメントブロックを実行するときは、いくつかの準備アクションが必要であり、実行が完了した後、いくつかの終了アクションを実行する必要があります。例:読み取りと書き込みの後にファイルを閉じる必要があり、データベースの読み取りと書き込みの後に接続を閉じる必要があり、リソースがロックおよびロック解除されます。この場合、Pythonはコンテキスト管理の概念を提供します。これは、コードブロックの実行前に準備アクションを処理し、コンテキストマネージャーを介して実行後に終了アクションを処理するために使用できます。
まず、コンテキストマネージャーを使用できない状況を見てください
f =open("log.txt","w")try:
f.write("hello")finally:
f.close()
コンテキストマネージャーを使用する
withopen("log.txt","w")as f:
f.write("hello")
ステートメントを閉じると、Pythonは自動的に f.close()
メソッドを呼び出します。
with
の後に open(" log.txt "、" w ")
ステートメントによって返されるオブジェクトの __enter__
メソッドが呼び出され、 __enter__
の戻り値が as
の後に変数に割り当てられます。
with
が実行されると、フロントエンドリターンオブジェクトの __exit__
メソッドが呼び出されます。
テストするクラスを書いてみましょう。
classContextTest:
def __enter__(self):print("エンターエンター!")return"Foo"
def __exit__(self,*args,**kwargs):print("出口に入る!")
def get_sample():returnContextTest()withget_sample()as sample:print(f"Sample: {sample}")
動作結果:
エンターエンター!
Sample: Foo
出口に入る!
上記のwithステートメントの原則に従って、クラスを使用して、ファイルを開くためのwithステートメントをサポートするクラスを実装します。
classFile:
def __init__(self, file_name: str, method: str):
self.file_obj =open(file_name, method)
def __enter__(self):return self.file_obj
def __exit__(self, exc_type, exc_val, exc_tb):
self.file_obj.close()print(f"type: {exc_type}")print(f"value: {exc_val}")print(f"traceback: {exc_tb}")withFile('demo.txt',"w")as f:
f.useless_func()
ここでも例外処理を実装しました。例外処理に関しては、withステートメントは次のように実行されます。
exc_type
、 exc_val
、 exc_tb
を __exit__
メソッドに渡します__exit__
メソッドが例外を処理できるようにします__exit__
がTrueを返す場合、例外は無視されます。__exit__
がTrue以外を返す場合、この例外はwithステートメントによってスローされます。出力結果は次のとおりです。
type:<class'AttributeError'>
value:'_io.TextIOWrapper' object has no attribute 'useless_func'
traceback:<traceback object at 0x000001D259D82908>Traceback(most recent call last):...
AttributeError:'_io.TextIOWrapper' object has no attribute 'useless_func'
from contextlib import contextmanager
@ contextmanager
def my_open(filename, mode):
file_obj =open(filename, mode)try:yield file_obj.readlines()
except Exception as e:
raise e
finally:
file_obj.close()if __name__ =='__main__':withmy_open(r'demo.txt','r')as f:for line in f:print(line)
降伏前のコードは __enter__
メソッドで実行され、降伏後のコードは __exit__
メソッドで実行されます。基本的に、これは __enter__
メソッドと __exit__
メソッドです。 @ contextmanager
のデコレータはジェネレータを受け入れるため、 yield
ステートメントを使用して with ... as var
の変数を出力すると、withステートメントは正常に機能します。
ファイルやデータベースなどの開閉を引き継ぐだけでなく、 @ contextmanager
の機能を使用して、いくつかの優れた機能を実行することもできます。特定のコードの実行の前後に特定のコードを自動的に実行する場合は、 @ contextmanager
を使用して実現することもできます。
@ contextmanager
def tag(name):print("<%s>"% name)yieldprint("</%s>"% name)withtag("h1"):print("hello")print("world")
# 出力
< h1>
hello
world
< /h1>
オブジェクトがコンテキストを実装していない場合、 with
ステートメントで使用することはできません。現時点では、 closeing
を使用してオブジェクトをコンテキストオブジェクトに変換できます。たとえば、 with
ステートメントでurlopen()
を使用します
from contextlib import closing
from urllib.request import urlopen
withclosing(urlopen('https://www.python.org'))as page:for line in page:print(line)
この魔法の「クロージング」のソースコードを見てみましょう
classclosing(AbstractContextManager):"""Context to automatically close something at the end of a block.
Code like this:withclosing(<module>.open(<arguments>))as f:<block>
is equivalent to this:
f =<module>.open(<arguments>)try:<block>finally:
f.close()"""
def __init__(self, thing):
self.thing = thing
def __enter__(self):return self.thing
def __exit__(self,*exc_info):
self.thing.close()
上記のクラスメソッドで行ったのと同じです〜
[ Liao XuefengのPythonチュートリアル-contextlib](https://www.liaoxuefeng.com/wiki/1016959663602400/1115615597164000)[ステートメントコンテキスト管理を使用したPythonの2つの実装方法](https://www.cnblogs.com/tkqasn/p/6003959.html)[Pythonでのwithの使用と原則](https://blog.csdn.net/u012609509/article/details/72911564)
Recommended Posts