ホームページ  >  記事  >  バックエンド開発  >  Python での with キーワードの使用の詳細な説明

Python での with キーワードの使用の詳細な説明

高洛峰
高洛峰オリジナル
2017-03-28 15:21:121590ブラウズ

この記事では主に 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 は任意の式にすることができます。一般的な実行プロセスは次のとおりです:

    EXPR を計算し、コンテキスト マネージャーの exit() メソッドを取得します。後の呼び出しのために保存されます
  1. 式が VAR として含まれている場合、コンテキスト マネージャーの enter() メソッドが呼び出され、EXPR の戻り値が VAR に割り当てられます
  2. BLOCK で式を実行します
  3. BLOCK の実行中に例外が発生した場合、コンテキスト マネージャーの exit() メソッドを呼び出します。例外の種類、値、およびトレースバック (つまり、sys.exc_info() の戻り値) は次のようになります。それ以外の場合は、コードでこのプロセスを表すために 3 つの None が渡されます。
  4. 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)

    このプロセスにはいくつかの詳細があります:

  5. enter() または exit( がない場合) ) コンテキスト マネージャーのメソッドを実行すると、インタープリターは AttributeError
  6. Occurs in BLOCK をスローします。例外の後、exit() メソッドが True とみなせる値を返した場合、例外はスローされず、後続のコードはスローされます。

    次に、上記のプロセスを 2 つの方法で実装します。
  7. コンテキスト マネージャー クラスの実装

    最初の方法は、インスタンス
  8. properties
db と、コンテキスト マネージャーに必要なメソッド enter() および exit() を含むクラスを実装することです。

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の実行処理を理解した上で、この実装は理解しやすいです。以下で紹介する実装方法は、理解するのが非常に複雑です。

ジェネレーターの使用
デコレーター

Pythonの標準ライブラリには、ジェネレーターを通じてコン​​テキストマネージャーを取得できるデコレーターがあります。ジェネレーター デコレーターを使用した実装プロセスは次のとおりです。

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) を呼び出します。ヘルパー関数はジェネレーター関数を呼び出し、ジェネレーターを作成します。

  1. ヘルパー関数は、このジェネレーターを GeneratorContextManager に渡し、コンテキスト マネージャーとして GeneratorContextManager のインスタンス オブジェクトを作成します。

  2. with 表达式调用实例对象的上下文管理器的 enter() 方法。

  3. enter() 方法中会调用这个生成器的 next() 方法。这时候,生成器方法会执行到 yield db 处停止,并将 db 作为 next() 的返回值。如果有 as VAR ,那么它将会被赋值给 VAR 。

  4. with 中的 BLOCK 被执行。

  5. BLOCK 执行结束后,调用上下文管理器的 exit() 方法。 exit() 方法会再次调用生成器的 next() 方法。如果发生 StopIteration 异常,则 pass 。

  6. 如果没有发生异常生成器方法将会执行 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 サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。