Pythonのyield
とfinally
を組み合わせた関数の返し値(ジェネレータ)は直接next
に渡してはならない。以下にその理由と例を示します。
def yielder():
try:
print('yielder setup')
yield 'text'
finally:
print('yielder teardown')
def f(text):
print(text)
for y in yielder():
f(y)
上記のコードを実行すると、出力は以下のようになります。
yielder setup
text
yielder teardown
しかし、next
を1回しか呼び出さないような使い方をすると、yielder setup
とtext
のみが出力され、yielder teardown
は呼ばれません。これは、finally
ブロックが実行されないためです。
この問題を解決するためには、finally
を使用してteardown
が呼ばれるようにすることができます。しかし、この関数を呼び出すときには注意が必要です。以下にその例を示します。
def yielder_with_finally():
try:
print('yielder setup')
yield 'text'
finally:
print('yielder teardown')
def f(text):
print(text)
for y in yielder_with_finally():
f(y)
上記のコードを実行すると、出力は以下のようになります。
yielder setup
text
yielder teardown
しかし、next
を使用してジェネレータを呼び出すと、yielder setup
、yielder teardown
、text
の順に出力され、予期せぬ実行順序になってしまいます。
以上のように、Pythonのyield
とfinally
を組み合わせる際には注意が必要です。特に、ジェネレータを直接next
に渡すことは避けるべきです。