Pythonがコンテキストマネージャを実現する方法
2461 ワード
問題
with文を使うために、自分でコンテキストマネージャを実現したいです。
ソリューション
新しいコンテキストマネージャを実現するための最も簡単な方法は、contexlibモジュール中の@contextmanagerを使用することである。コードブロック計時機能を実装したコンテキストマネージャの例である。
以下はより上位のコンテキストマネージャで、リストオブジェクト上のあるトランザクションを実行します。
通常、コンテキストマネージャを書くには、クラスを定義する必要があります。enter_()ひゅうっとexit_()方法は、以下の通りです。
以上がPythonのコンテキストマネージャを実現する方法の詳細です。Pythonのコンテキストマネージャ実現に関する詳細については、他の関連記事に注目してください。
with文を使うために、自分でコンテキストマネージャを実現したいです。
ソリューション
新しいコンテキストマネージャを実現するための最も簡単な方法は、contexlibモジュール中の@contextmanagerを使用することである。コードブロック計時機能を実装したコンテキストマネージャの例である。
import time
from contextlib import contextmanager
@contextmanager
def timethis(label):
start = time.time()
try:
yield
finally:
end = time.time()
print('{}: {}'.format(label, end - start))
# Example use
with timethis('counting'):
n = 10000000
while n > 0:
n -= 1
関数timethis()
において、yield
の前のコードはコンテキストマネージャにおいて__enter__()
の方法として実行され、yield
の後のコードは __exit__()
の方法として実行される。異常が発生したら、異常はyield文に投げられます。以下はより上位のコンテキストマネージャで、リストオブジェクト上のあるトランザクションを実行します。
@contextmanager
def list_transaction(orig_list):
working = list(orig_list)
yield working
orig_list[:] = working
このコードの役割は、リストの変更はすべてのコードの実行が完了し、異常が発生しない場合にのみ有効となります。ここで実証します。
>>> items = [1, 2, 3]
>>> with list_transaction(items) as working:
... working.append(4)
... working.append(5)
...
>>> items
[1, 2, 3, 4, 5]
>>> with list_transaction(items) as working:
... working.append(6)
... working.append(7)
... raise RuntimeError('oops')
...
Traceback (most recent call last):
File "<stdin>", line 4, in <module>
RuntimeError: oops
>>> items
[1, 2, 3, 4, 5]
>>>
討論する通常、コンテキストマネージャを書くには、クラスを定義する必要があります。enter_()ひゅうっとexit_()方法は、以下の通りです。
import time
class timethis:
def __init__(self, label):
self.label = label
def __enter__(self):
self.start = time.time()
def __exit__(self, exc_ty, exc_val, exc_tb):
end = time.time()
print('{}: {}'.format(self.label, end - self.start))
これも難しいことではないですが、比較的簡単に@contextmanager
注釈の関数を使って書くとちょっと味気ないです。@contextmanager
は、単に含まれるコンテキスト管理関数から書くべきである。もしいくつかのオブジェクト(例えば、ファイル、ネットワーク接続、またはロック)があったら、with
のステートメントをサポートする必要があります。 __enter__()
の方法と__exit__()
の方法を単独で実現する必要があります。以上がPythonのコンテキストマネージャを実現する方法の詳細です。Pythonのコンテキストマネージャ実現に関する詳細については、他の関連記事に注目してください。