この記事では主に Python での with キーワードの詳細な使用法に関する関連情報を紹介します。Python では、with キーワードはコンテキスト プロトコル オブジェクトの実装を管理するための優れたツールです。必要な方は参照してください。
" > Python 2.5 では、 with キーワードが追加されました。これにより、一般的に使用される try ... を除いて ... Finally ... パターンが再利用しやすくなります。最も古典的な例を見てください:with open('file.txt') as f: content = f.read()コードでは、コード ブロックの実行中に何が起こっても、ファイルは最終的に閉じられます。コード ブロックの実行中に例外が発生した場合、例外がスローされる前にプログラムが閉じられます。 別の例を見てください。データベース トランザクション リクエストを開始するときは、次のようなコードがよく使用されます:
db.begin() try: # do some actions except: db.rollback() raise finally: db.commit()トランザクション リクエストを開始する操作がキーワードを使用してサポートされるように変更されている場合は、次のようなコードを使用します。 :
with transaction(db): # do some actions以下では、with の実行プロセスを詳しく説明します。
with の一般的な実行プロセスは、2 つの一般的な方法で実装されます
expression の構造は次のとおりです。 with EXPR as VAR:
BLOCK
ここで: VAR はオプションであるため、EXPR は任意の式にすることができます。一般的な実行プロセスは次のとおりです:
mgr = (EXPR) exit = type(mgr).exit # 这里没有执行 value = type(mgr).enter(mgr) exc = True try: try: VAR = value # 如果有 as VAR BLOCK except: exc = False if not exit(mgr, *sys.exc_info()): raise finally: if exc: exit(mgr, None, None, None)
このプロセスにはいくつかの詳細があります:
class transaction(object): def init(self, db): self.db = db def enter(self): self.db.begin() def exit(self, type, value, traceback): if type is None: db.commit() else: db.rollback()withの実行処理を理解した上で、この実装は理解しやすいです。以下で紹介する実装方法は、理解するのが非常に複雑です。
ジェネレーターの使用
デコレーター
from contextlib import contextmanager @contextmanager def transaction(db): db.begin() try: yield db except: db.rollback() raise else: db.commit()一見すると、この実装は単純ですが、そのメカニズムはより複雑です。その実行プロセスを見てみましょう: Python インタープリターが yield キーワードを認識した後、def は通常の関数の代わりにジェネレーター
function
を作成します (私はクラス定義外のメソッドの代わりに関数を使用するのが好きです)。デコレーター contextmanager が呼び出され、ヘルパー メソッドを返します。このメソッドは、呼び出された後に GeneratorContextManager インスタンスを生成します。最後に、with 式の EXPR は、contentmanager デコレータによって返されるヘルパー関数を呼び出します。
with 式は、実際にヘルパー関数を呼び出すtransaction(db) を呼び出します。ヘルパー関数はジェネレーター関数を呼び出し、ジェネレーターを作成します。with 表达式调用实例对象的上下文管理器的 enter() 方法。
enter() 方法中会调用这个生成器的 next() 方法。这时候,生成器方法会执行到 yield db 处停止,并将 db 作为 next() 的返回值。如果有 as VAR ,那么它将会被赋值给 VAR 。
with 中的 BLOCK 被执行。
BLOCK 执行结束后,调用上下文管理器的 exit() 方法。 exit() 方法会再次调用生成器的 next() 方法。如果发生 StopIteration 异常,则 pass 。
如果没有发生异常生成器方法将会执行 db.commit() ,否则会执行 db.rollback() 。
再次看看上述过程的代码大致实现:
def contextmanager(func): def helper(*args, **kwargs): return GeneratorContextManager(func(*args, **kwargs)) return helper class GeneratorContextManager(object): def init(self, gen): self.gen = gen def enter(self): try: return self.gen.next() except StopIteration: raise RuntimeError("generator didn't yield") def exit(self, type, value, traceback): if type is None: try: self.gen.next() except StopIteration: pass else: raise RuntimeError("generator didn't stop") else: try: self.gen.throw(type, value, traceback) raise RuntimeError("generator didn't stop after throw()") except StopIteration: return True except: if sys.exc_info()[1] is not value: raise
总结
Python的 with 表达式包含了很多Python特性。花点时间吃透 with 是一件非常值得的事情。
一些其他的例子
锁机制
@contextmanager def locked(lock): lock.acquired() try: yield finally: lock.release()
标准输出重定向
@contextmanager def stdout_redirect(new_stdout): old_stdout = sys.stdout sys.stdout = new_stdout try: yield finally: sys.stdout = old_stdout with open("file.txt", "w") as f: with stdout_redirect(f): print "hello world"
以上がPython での with キーワードの使用の詳細な説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。