__enter__ と __exit__ プロトコル
特殊メソッドのプロトコルを使ってコンテキストマネージャーを作成します。
「__enter__ と __exit__ プロトコル」はCoddyKit上の無料Python Academyレッスンです。 これはレッスン2/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはPython Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Python Academyコースには全4レッスンが含まれています。
コンテキストマネージャープロトコル
__enter__と__exit__を定義するオブジェクトはすべてコンテキストマネージャーであり、withと一緒に使用できます。
class Managed:
def __enter__(self):
print("entering")
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print("exiting")
return False
with Managed() as m:
print("inside")__enter__の返り値
__enter__はwithブロックの開始時に呼び出されます。その返り値が、asの後にある変数へ代入されます。
class Resource:
def __enter__(self):
self.value = 42
return self # bound to 'r'
def __exit__(self, *args):
self.value = None
return False
with Resource() as r:
print(r.value) # 42__exit__の引数
__exit__(exc_type, exc_val, exc_tb)は、エラーが発生した場合に例外情報を受け取ります。例外がない場合、3つの値はすべてNoneです。
class Safe:
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
if exc_type is ValueError:
print(f"Suppressed ValueError: {exc_val}")
return True # suppress the exception
return False # re-raise anything else
with Safe():
raise ValueError("oops") # suppressed例外の抑制
__exit__からTrueを返すと、例外を抑制できます。False(または何も返さない場合)は、例外を伝播させます。
class Ignore:
def __enter__(self): return self
def __exit__(self, *args): return True # swallow all exceptions
with Ignore():
1 / 0
print("continues here")データベース接続の例
典型的な使用例は、開始時に接続を取得し、終了時にコミットまたはロールバックして閉じることです。
class DBConn:
def __enter__(self):
self.conn = connect_db()
return self.conn
def __exit__(self, exc_type, exc_val, exc_tb):
if exc_type:
self.conn.rollback()
else:
self.conn.commit()
self.conn.close()
return Falseタイマーのコンテキストマネージャー
__enter__で開始時刻を記録し、__exit__で差分を計算することで、経過時間を測定できます。
import time
class Timer:
def __enter__(self):
self.start = time.perf_counter()
return self
def __exit__(self, *args):
self.elapsed = time.perf_counter() - self.start
print(f"Elapsed: {self.elapsed:.3f}s")
return False
with Timer():
sum(range(1_000_000))コンテキストマネージャーのネスト
1行のwithで複数のコンテキストマネージャーを組み合わせられます。
with open("in.txt") as src, open("out.txt", "w") as dst:
dst.write(src.read())再利用可能なマネージャーと1回限りのマネージャー
__enter__が毎回新しいリソースを確保するコンテキストマネージャーは再利用可能です。ロックを1回だけ保持する場合のように、内部状態を使い果たすものは再利用できない場合があります。
class Reusable:
def __enter__(self):
return []
def __exit__(self, *a):
return False
for _ in range(3):
with Reusable() as lst:
lst.append(1)
print(lst) # [1] each time__aenter__と__aexit__(非同期)
非同期コンテキストマネージャーでは、__aenter__と__aexit__のコルーチンを定義し、async withを使用します。
class AsyncDB:
async def __aenter__(self):
self.conn = await connect()
return self.conn
async def __aexit__(self, *args):
await self.conn.close()
# async with AsyncDB() as conn:
# ...ファイルオブジェクトのラップ
Pythonのファイルオブジェクトは、すでにコンテキストマネージャープロトコルを実装しています。そのため、f.close()を手動で呼び出さないでください。
with open("data.txt", "r") as f:
data = f.read()
# file is closed here automatically
print(f.closed) # TrueLockの実装
スレッドロックはコンテキストマネージャーです。__enter__がロックを取得し、__exit__が解放します。
import threading
lock = threading.Lock()
def update_shared():
with lock:
# critical section
passクイックチェック
例外を抑制するには、__exit__は何を返す必要がありますか?
まとめ
__enter__と__exit__を実装して、コンテキストマネージャーを作成します。__enter__からリソースを返し、__exit__でクリーンアップと例外の抑制を処理します。
よくある質問
「__enter__ と __exit__ プロトコル」レッスンは無料ですか?
はい。「__enter__ と __exit__ プロトコル」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Python Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Python Academyコースには全4レッスンが含まれています。
「__enter__ と __exit__ プロトコル」で何を学びますか?
特殊メソッドのプロトコルを使ってコンテキストマネージャーを作成します。 ブラウザで直接実行するハンズオンコードでPython Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Python Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのPython Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン2/4です。
「__enter__ と __exit__ プロトコル」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このPython Academyレッスンでコードを書いて実行できますか?
はい。すべてのPython Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- with 文を深く理解する
- __enter__ と __exit__ プロトコル
- contextlib: @contextmanager
- 実践的なコンテキストマネージャーパターン