Pythonのwith文の使い方

王林
王林転載
2023-05-25 17:22:062034ブラウズ

ステートメント本体 (with-body): with ステートメントでラップされたコード ブロックは、ステートメント本体を実行する前にコンテキスト マネージャーの enter() メソッドを呼び出し、ステートメント本体の実行後に exit() メソッドが実行されます。実行されました。

基本構文と動作原理

with ステートメントの構文形式は次のとおりです。

リスト 1. with ステートメントの構文形式with ステートメント

with context_expression [as target(s)]:

with-body

ここで、 contextexpression は、コンテキスト マネージャー オブジェクトを返します。 as 句 target に as 句を指定すると、コンテキストマネージャの _enter() メソッドの戻り値が target に代入されます。 target は単一の変数、または「()」で囲まれたタプルにすることができます (「,」だけで区切られた変数のリストにすることはできません。「()」を追加する必要があります)。

Python では、いくつかの組み込みオブジェクトが改善され、コンテキスト マネージャーのサポートが追加されました。コンテキスト マネージャーは、ファイルの自動クローズ、スレッド ロックの自動的な取得と解放など、with ステートメントで使用できます。ファイルを操作したいとします。with ステートメントを使用して、次のコードを作成できます。

リスト 2. with ステートメントを使用して、ファイル オブジェクトを操作します。

with open(r'somefileName' ) as somefile:

for line in somefile:

print line

# ...more code

withここでは、処理内容に関係なく、ステートメントが使用されます。ファイル処理中に例外が発生したかどうかにかかわらず、with ステートメントの実行後に、開いているファイル ハンドルが確実に閉じられるようにすることができます。従来の try/finally パラダイムを使用する場合は、次のようなコードを使用する必要があります。

リスト 3. ファイル オブジェクトを操作するための Try/finally モード

somefile = open(r' somefileName')

try:

for line in somefile:

print line

# ...その他のコード

最後に:

somefile.close()

それに比べて、with ステートメントを使用するとコーディングの量を減らすことができます。コンテキスト管理プロトコルをサポートするために、スレッド化、10 進数などのモジュールも追加されました。

PEP 0343 では、with ステートメントの実装について説明しています。 with ステートメントの実行プロセスは、次のコード ブロックに似ています。

リスト 4. with ステートメントの実行プロセス

# context_manager = context_expression

exit = type(context_manager) .__exit__

Value = type(context_manager).__enter__(context_manager)

exc = True # True は、例外が発生した場合でも通常の実行を意味します。無視されます。False は例外を再スローすることを意味し、例外を処理する必要があります。 Process

try:

try:

target = value # if the as 句is used

with-body #Execute with-body

例外: # 実行中に例外が発生する

# exc = False

# __exit__ が True を返した場合の場合、例外は無視されます。False が返された場合、例外は再スローされます

#外部コードによる例外処理

##if not exit(context_manager, *sys.exc_info()):

raise

finally:

#通常終了するか、ステートメント本体の Break/Continue/Return ステートメントを介して終了します

または例外を無視しますそして exit

if exc:

exit (context_manager, None, None, None)

# デフォルトでは None を返します、ブールコンテキストでは None は False とみなされます

context_expressionを実行してコンテキストマネージャーcontext_managerを生成します。

コンテキスト マネージャーの enter() メソッドを呼び出します。as 句が使用されている場合は、enter() メソッドの戻り値を as 句内のターゲットに割り当てます。

実行文本体 with-body

実行中に例外が発生したかどうかに関係なく、実行コンテキスト マネージャーの exit() メソッドが実行されます。メソッドは実行を担当し、リソースの解放などの「クリーニング」作業を行います。実行中に例外が発生しない場合、またはステートメント本体で Break/Continue/Return ステートメントが実行される場合は、パラメータとして None を指定して exit(None, None, None) を呼び出します。実行中に例外が発生する場合は、sys.excinfo を使用します。情報は、パラメータ call _exit(exc_type, exc_value, exc_traceback) です。

例外が発生したときに、exit(type, value,traceback) が False を返した場合、例外は再スローされ、with 以外のステートメント ロジックが例外の処理に使用されます。これも一般的なものです。練習してください。True が返された場合は、例外を無視し、例外を処理しません。

カスタム コンテキスト マネージャー

開発者は、コンテキスト管理プロトコルをサポートするクラスをカスタマイズできます。カスタム コンテキスト マネージャーは、コンテキスト管理プロトコルで必要な enter() メソッドと exit() メソッドを実装する必要があります。

Contextmanager._enter(): コンテキスト マネージャーのランタイム コンテキストを入力し、ステートメント本体で実行します。前に電話した。 with ステートメントは、メソッドの戻り値を as 句のターゲット (指定されている場合) に割り当てます。

Contextmanager._exit(exc_type, exc_value, exc_traceback): コンテキスト マネージャーに関連するランタイム コンテキストを終了し、発生した例外を処理するかどうかを示すブール値を返します。パラメータは、終了操作を引き起こした例外を示します。終了中に例外が発生しなかった場合、3 つのパラメータはすべて None になります。例外が発生した場合は戻ります。

true は例外を処理しないことを意味します。それ以外の場合、例外はメソッド終了後に再スローされ、with ステートメントの外側のコード ロジックによって処理されます。このメソッド内で例外が発生した場合は、statement-body のステートメントによって発生した例外が置き換えられます。例外を処理するときは、明示的に例外を再スローしないでください。つまり、パラメーターを通じて渡された例外を再スローすることはできません。戻り値を False に設定するだけで済みます。次に、コンテキスト管理コードは、exit() が例外の処理に失敗したかどうかを検出します。

以下は、カスタム コンテキスト マネージャーを構築する方法を示す簡単な例です。コンテキスト マネージャーは enter() メソッドと exit() メソッドの両方の定義を提供する必要があることに注意してください。どちらかが存在しない場合は AttributeError が発生します。with ステートメントは最初に exit() メソッドが提供されているかどうかを確認し、次に enter() メソッドが提供されているかどうかを確認します。 ()メソッドが定義されています。

リソース DummyResource があるとします。このリソースは、アクセスする前に割り当て、使用後に解放する必要があります。割り当て操作は enter() メソッドに配置でき、解放操作は exit( ) 方法。 。わかりやすくするために、現在の操作を示すために print ステートメントのみが使用され、実際のリソースの割り当てと解放は行われません。

#リスト 5. with ステートメントをサポートするカスタム オブジェクト

class DummyResource:

def __init__(self, tag):

Self.tag = tag

print 'リソース [%s]' % tag

def __enter__(self):

print '[Enter %s]: リソースの割り当て.' % self.tag

Return self # さまざまなオブジェクトを返すことができます

def __exit__(self, exc_type, exc_value, exc_tb):

print '[Exit %s ]: 空きリソース。' % self.tag

exc_tb が None の場合:

print '[Exit %s]: 例外なく終了しました。' % self.tag

else:

print '[Exit %s]: Exited with例外が発生しました。' % self.tag

return False # 省略可能、デフォルトのNoneもFalseとみなされます

DummyResource の Enter() は、それ自体への参照を返します。この参照は、as 句のターゲット変数に割り当てることができます。戻り値の型は、実際のニーズに応じて別の型に設定できます。それ自体がコンテキスト マネージャー オブジェクトになります。

変数 exctb が exit() メソッドで検出されました。None でない場合は、例外が発生したことを意味します。False が返された場合は、例外を外部コード ロジックで処理する必要があることを意味します。例外は発生しません (デフォルト) 戻り値は None で、ブール環境では False とみなされます。ただし、例外は発生しないため、_exit() の 3 つのパラメータは None です。コンテキスト管理コードはこの状況を検出して処理できます。それは普通に。

with ステートメントで DummyResource にアクセスするには、次のようにします。

リスト 6. with ステートメントをサポートするカスタム オブジェクトの使用

with DummyResource( 'Normal' ):

print '[with-body] 例外なしで実行します。'

with DummyResource('With-Exception'):

print '[with- body] 例外を発生させて実行します。'

raise Exception

print '[with-body] 例外を発生させて実行します。statement-body の終了に失敗しました!'

最初の実行with ステートメントの結果は次のとおりです。

リスト 7. with ステートメント 1 の実行結果

## Resource [Normal]

[Enter Normal]: Allocate resource.

[with-body] 例外なく実行します。

[通常の終了]: 空きリソース。

# [通常の終了]: 例外なく終了します。

通常の実行では、ステートメント本体 with-body が最初に実行され、次に exit() メソッドが実行されてリソースが解放されることがわかります。

2 番目の with ステートメントの実行結果は次のとおりです。

リスト 8. with ステートメント 2 の実行結果

Resource [With- Exception] [Enter With-Exception]: リソースを割り当てます。

[with-body] Run with example.

[Exit With-Exception]: リソースを解放します。

[Exit With-Exception]: 例外が発生して終了しました。

トレースバック (最新の呼び出しは最後):

ファイル "G:/demo"、行 20、発生中Exception

Exception

with-bodyで例外が発生した場合、with-bodyは実行されていないが、リソースは解放されることが保証されていることがわかります。生成された例外は、with ステートメントのキャプチャ処理の外側のコード ロジックによって引き起こされます。

コンテキスト マネージャーをカスタマイズして、データベース接続、共有リソースのアクセス制御など、ソフトウェア システム内のリソースを管理できます。 Python オンライン ドキュメント「Writing Context Managers」には、データベース接続を管理するためのコンテキスト マネージャーの簡単な例が記載されています。

Contextlib モジュール

contextlib モジュールは、デコレーター contextmanager、ネストされた関数、コンテキスト マネージャー クロージングの 3 つのオブジェクトを提供します。これらのオブジェクトを使用すると、既存のジェネレーター関数またはオブジェクトをラップし、コンテキスト管理プロトコルのサポートを追加できるため、with ステートメントをサポートするために特別にコンテキスト マネージャーを作成する必要がなくなります。

Decorator contextmanager

Contextmanager はジェネレーター関数を装飾するために使用されます。ジェネレーター関数が装飾された後、コンテキスト マネージャーが返され、その enter() メソッドと exit() メソッドは次のとおりです。前のイテレータの代わりにそれを提供する責任があります。装飾されたジェネレーター関数は 1 つの値のみを生成でき、それ以外の場合は例外 RuntimeError が発生します。生成された値は、as 句が使用されている場合、as 句内のターゲットに割り当てられます。簡単な例を見てみましょう。

リスト 9. デコレータ contextmanager の使用例

from contextlib import contextmanager

@contextmanager

def Demon():

print '[リソースの割り当て]'

print '__enter__ で yield-statement が実行される前のコード'

yield '*** contextmanager デモ ***'

print 'yield-statement が __exit__ で実行された後のコード'

print '[無料リソース]'

demo() を値として使用:

print '割り当てられた値: % s' % value

結果出力は次のとおりです。

リスト 10. Contextmanager の使用例の実行結果

[リソースの割り当て]

yield-statement 実行前のコードは __enter__

Assigned Value: *** contextmanager デモ ***

yield-statement 実行後のコードは __exit__

[Freeリソース]

ジェネレーター関数の yield 前のステートメントは enter() メソッドで実行され、yield 後のステートメントは exit() メソッドで実行され、yield によって生成された値が代入されていることがわかります。 as 句の値変数。

contextmanager は enter() / exit() の記述を省略するだけで、リソースの「取得」と「クリーニング」は担当しないことに注意してください。「取得」操作は実行する必要があります。 yield ステートメントで定義されていました。以前は、「クリーニング」操作は yield ステートメントを定義する必要がありました。そのため、with ステートメントは、enter() / exit() メソッドの実行時にこれらのステートメントを実行してリソースを取得/解放します。リソースを含むロジック制御はジェネレーター関数に実装する必要があります。 アクセス エラーが発生した場合は、適切な例外をスローします。

Functionnested

Nested では、複数のコンテキスト マネージャーをまとめて、ネストされた with ステートメントの使用を回避できます。

リスト 11. ネストされた構文

nested(A(), B(), C()) as (X, Y, Z):

#with-body コードはここにあります

次と同様です:

リスト 12. ネストされた実行プロセス

A() を X として使用します:

with B() as Y:

with C() as Z:

## with-body code here

例外が発生することに注意してください最後に、コンテキスト マネージャーの exit() メソッドが例外処理に対して False を返した場合、外側のコンテキスト マネージャーは例外を検出しません。

#コンテキスト マネージャーのクロージング

# クロージングの実装は次のとおりです。

リスト 13. コンテキスト マネージャのクロージングの実装

クラスクローズ(オブジェクト):

# ここでヘルプドキュメント

def __init__(self, thing):

self.thing = thing

def __enter__(self):

return self.thing

def __exit__(self, *exc_info):

self.thing.close()

コンテキスト マネージャーは、ラップされたオブジェクトを as 句のターゲット変数に割り当て、with-body の実行後に開かれたオブジェクトが確実に閉じられるようにします。クローズコンテキストマネージャーによってラップされたオブジェクトは、close() メソッドの定義を提供する必要があります。そうでない場合は、実行中に AttributeError が報告されます。

リスト 14. クロージングをサポートするカスタム オブジェクト

class ClosingDemo(object):

def __init__(self):

self.acquire()

defacquire(self):

print 'リソースを取得します。'

def free(self):

print 'クリーン取得したリソースをすべてアップします。'

def close(self):

self.free()

with Closing(ClosingDemo()):

print 'リソースの使用'

結果の出力は次のとおりです:

リスト 15. カスタム終了オブジェクトの出力結果

リソースを取得します。 リソースの使用

取得したリソースをクリーンアップします。

クロージングは​​、ネットワーク接続、データベース接続など、close() 実装を提供するオブジェクトに適用できます。また、これを渡すこともできます。クラスをカスタマイズするとき、インターフェイス close() を使用して、必要なリソースの「クリーニング」作業を実行します。

以上がPythonのwith文の使い方の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はyisu.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。