ホームページ  >  記事  >  バックエンド開発  >  Python コンテキスト マネージャーとブロックの詳細な説明

Python コンテキスト マネージャーとブロックの詳細な説明

巴扎黑
巴扎黑オリジナル
2017-09-11 10:51:49982ブラウズ

この記事では、主に Python コンテキスト マネージャーと with ブロックの関連情報を詳しく紹介します。興味のある方は、

コンテキスト マネージャー オブジェクトを参照してください。 for ステートメントを管理するためにイテレータが存在するのと同じように、with ステートメントを管理するために存在します。

with ステートメントの目的は、try/finally パターンを簡素化することです。このモードは、コードの一部の実行が終了した後に、例外、return ステートメント、または sys.exit() 呼び出しによってコードが終了した場合でも、指定された操作が確実に実行されるようにするために使用されます。実行されました。通常、finally 句のコードは、重要なリソースを解放したり、一時的に変更された状態を復元したりするために使用されます。

==コンテキストマネージャープロトコルには、enter と exit の 2 つのメソッドが含まれています==。 with ステートメントの実行が開始されると、コンテキスト マネージャー オブジェクトで enter メソッドが呼び出されます。 with ステートメントの実行が終了すると、コンテキスト マネージャー オブジェクトで exit メソッドが呼び出され、finally 句として機能します。

==with の後に式を実行した結果は、コンテキスト マネージャー オブジェクトです。値をターゲット変数 (as 句) にバインドすると、コンテキスト マネージャー オブジェクトで Enter メソッドを呼び出した結果になります。 with ステートメントの as 句はオプションです。 open 関数の場合、ファイルへの参照を取得するには as 句を追加する必要があります。ただし、一部のコンテキスト マネージャーは、ユーザーに提供する有用なオブジェクトがないため、None を返します。

with open('mirror.py') as fp:
  ...

カスタマイズされたコンテキストクラス:

class A:
  def __init__(self, name):
    self.name = name

  def __enter__(self):
    print('enter')
    return self.name

  def __exit__(self, exc_type, exc_val, exc_tb):
    print('gone')

with A('xiaozhe') as dt:
  print(dt)


contextlibモジュール

contextlibモジュールには、より広範囲に使用できるいくつかのクラスとその他の関数もあります。

クロージング: オブジェクトが close() メソッドを提供しているが、

enter/exit

プロトコルを実装していない場合、この関数を使用してコンテキスト マネージャーを構築できます。

suppress: 指定された例外を一時的に無視するコンテキストマネージャーを構築します。 @contextmanager: ==このデコレーターは、単純なジェネレーター関数をコンテキストマネージャーに変換します==。そのため、マネージャープロトコルを実装するクラスを作成する必要はありません。 ContextDecorator: これは、クラスベースのコンテキスト マネージャーを定義するために使用される基本クラスです。このコンテキスト マネージャーは、関数を修飾するために使用することもでき、管理されたコンテキストで関数全体を実行します。
ExitStack: このコンテキスト マネージャーは、複数のコンテキスト マネージャーに入ることができます。 with ブロックの最後で、ExitStack はスタック内の各コンテキスト マネージャーの
exit
メソッドを後入れ先出しの順序で呼び出します。
==最も広く使用されているのは @contextmanager デコレーターなので、特に注意してください。このデコレーターも反復とは関係なく、yield ステートメント == を使用するため、混乱を招きます。

@contextmanager

@contextmanager デコレータを使用すると、コンテキスト マネージャーを作成するための定型コードの量を減らすことができ、enter メソッドと exit メソッドの完全なクラス定義を記述する代わりに、yield ステートメントを含むジェネレーターを実装するだけで済みます。目的の生成 Enter メソッドに値を返させます。

@contextmanager で装飾されたジェネレーターでは、yield ステートメントの機能は、関数の定義本体を 2 つの部分に分割することです。 ==yield ステートメントの前のすべてのコードは、with ブロックの先頭で実行されます (つまり、 、インタープリターが enter メソッドを呼び出すとき)、yield ステートメントに続くコードは、with ブロックの最後 (つまり、exit メソッドが呼び出されるとき) で == を実行します。

import contextlib

@contextlib.contextmanager
def test(name):
  print('start')
  yield name
  print('end')

with test('zhexiao123') as dt:
  print(dt)
  print('doing something')


実装原則

contextlib.contextmanager デコレータは、関数を enter メソッドと exit メソッドを実装するクラスにラップします。クラスの名前は _GeneratorContextManager です。

このクラスの enter メソッドには次の関数があります:

1. ジェネレーター関数を呼び出し、ジェネレーター オブジェクト (ここでは gen と呼びます) を保存します。

2. next(gen) を呼び出し、yield キーワードの場所まで実行します。

3. next(gen) によって生成された値を返し、生成された値を with/as ステートメント内のターゲット変数にバインドできるようにします。

with ブロックが終了すると、exit メソッドは次のことを行います:

1. 例外が exc_type に渡されたかどうかを確認し、渡された場合は gen.throw(Exception) を呼び出し、ジェネレーター関数定義に yield を含めます。 body キーワードを含む行は例外をスローします。
2. それ以外の場合は、next(gen) を呼び出して、ジェネレーター関数定義本体の yield ステートメントの後のコードの実行を続けます。


例外処理

例外が処理されたことをインタープリタに伝えるために、exit メソッドは True を返し、インタープリタは例外を抑制します。 exit メソッドが明示的に値を返さない場合、インタープリタは None を取得し、例外をバブルアップします。

@contextmanager デコレーターを使用する場合、デフォルトの動作は逆になります。デコレーターによって提供される exit メソッドは、ジェネレーターに送信されたすべての例外が処理されたと想定するため、例外は抑制される必要があります。 @contextmanager に例外を抑制させたくない場合は、装飾された関数で例外を明示的に再スローする必要があります。

上記のコードにはバグがあります。with ブロックで例外がスローされた場合、Python インタープリターはそれをキャッチし、テスト関数の yield 式で再度スローします。ただし、エラーを処理するコードがないため、テスト関数は中止されます。

使用 @contextmanager 装饰器时,要把 yield 语句放在 try/finally 语句中,因为我们永远不知道上下文管理器的用户会在 with 块中做什么。


import contextlib

@contextlib.contextmanager
def test(name):
  print('start')

  try:
    yield name
  except:
    raise ValueError('error')
  finally:
    print('end')

with test('zhexiao123') as dt:
  print(dt)
  print('doing something')

以上がPython コンテキスト マネージャーとブロックの詳細な説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

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