コンテキストマネージャーの__exit__は、発電機の内部にトリガーされるのはいつですか?

StackOverflow https://stackoverflow.com/questions/19825106

質問

ジェネレーターをコルーチンとして使用して、タスクスケジューラのようなものを作成しています。以下のコードでは、 print cleanup 決定論的に。

私の相互作用から、オブジェクトをガベージコレクターにリリースすると、コンテキストマネージャーが終了するように思われます。しかし、私はGCのタイミングに頼るよりもよく知っています。それは本当にGCを呼んでいますか __exit__ それとも別のメカニズムですか?

どうすれば厳密に強制することができますか print 'cleanup'?

>>> from contextlib import contextmanager
>>> @contextmanager
... def foo():
...     print 'setup'
...     try:
...         yield
...     finally:
...         print 'cleanup'
... 
>>> def bar():
...     with foo():
...         while True:
...             yield 'bar'
... 
>>> b = bar()
>>> b.next()
setup
'bar'
>>> b = None
cleanup
役に立ちましたか?

解決

はい、GCは電話をかけています __del__ 発電機のクリーンアップフック、それは GeneratorExit 発電機関数で発電機を終了する(呼び出すことによって generator.close()).

これは、コンテキストマネージャーを意味します __exit__ メモリからジェネレーター関数がクリアされるたびにフックが呼び出されます。

最初にジェネレーターを手動で閉じることができます generator.close():

b.close()

他のヒント

ジェネレーターを出させる必要があります。ジェネレーターの性質が永遠に見える場合、Gen.Throw()を使用して、発電機の例外を提起できます。

実際、私はジェネレーターの仕様を見たばかりで、それらはまさにこれを行う方法()を持っています(ジェネレーター内でgeneratorexit()例外が提起されます。したがって、gen.close()に電話してください。コンテキストマネージャーはすべてを呼び出します 出口 方法。ジェネレーターは例外を食べるので、トライブロックでclose()コールをラップする必要はありません。

>>> b= bar()
>>> b.next()
setup
'bar'
>>> b.close()
cleanup
>>>
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top