2017-11-08 15 views
2

CODE1:なぜ以下の2つのコードの結果が異なるのですか?

def af(): 
    a=65 
    try: 
     yield a 

    finally: 
     print('end') 

print(af().next()) 

CODE2:

end 
65 

しかしCODE2の結果は:

def af(): 
    a=65 
    try: 
     yield a 

    finally: 
     print('end') 

g=af() 
print(g.next()) 

CODE1の結果は

65 
end 
Pythonは

print(af().next()) 

 af().next() 

介して取得し、ジェネレータオブジェクトの参照カウントは、この時点で0に落ちるが、Pythonが強制的に発電機のcloseメソッドを呼び出して実行するスニペット1において

答えて

0

finallyブロックと__exit__メソッドを実行するので、ブロックfinallyはブロックendを出力します。

そしてprint(af().next())ランとプリント65print一部。


Pythonは finallyブロックがこの時点では実行されないよう

print(g.next()) 

ジェネレータオブジェクトは、g変数から参照することによって生かされる実行スニペット2において

、及びパイソンプリント65

次に、インタプリタシャットダウン時、ジェネレータの参照カウントが0まで低下し、closeendを印刷finallyブロックを、トリガー。これは保証されていません - Pythonはインタプリタのシャットダウン時に生存しているオブジェクトがデストラクタを呼び出すことを保証しませんが、それが起こりました。

+0

はい、あなたは私の疑問を解決しました、ありがとう! –

0

ジェネレータ自体がクリーンアップされるのは問題です。ジェネレータへの参照を保存しないときは、最後の参照がスコープから外れると(少なくともCPythonでは、参照されているため、ここでは「参照」インタプリタが使用されます)、ジェネレータはクリーンアップされますこれは直ちにGeneratorExitをジェネレータ本体に持ち上げ、finallyブロックに達して印刷します。あなたの最初の例で

print(af().next())瞬間next戻り、発電機への生活の参照がもはや存在しないので、それは(printがまだ呼び出されていない、すぐに実行するfinallyブロックを引き起こして、クリーンアップだ、我々はしていますまだそれに渡す引数を取得している)。 g(この場合はプログラムの終了時に)破壊されるまで、発電を再開する準備が残るように、あなたの2番目の例では

は、あなたが(それがyield次再開する)、gに発電機への参照を保存しました。printが終了すると、プログラムはプログラムのクリーンアップを終了し、ブロックfinallyが実行されます。

このようなグローバルのクリーンアップは保証されていません。 CPython 2.7ではシャットダウン時にすべてのグローバルがNoneに設定されますが、これはあなたにこの動作をもたらしますが、契約上の問題ではありません。あなたは明示的にそれを実行するか、またはそれが本当にきれいになることを確かめるために、closeジェネレータを(必要ならばcontextlib.closing経由で)実行したいでしょう。

+0

あなたの答えに感謝し、それは私の疑問を解決しました! –

関連する問題