Python 2では、関数定義でreturnとyieldが一緒になったときにエラーが発生しました。ただし、このコードではPython 3.3
def f():
return 3
yield 2
x = f()
print(x.__next__())
yieldで関数でreturnが使用されているというエラーはありません。ただし、関数__next__
が呼び出されると、例外StopIterationがスローされます。返された値だけではない理由3
?この戻り値は何とか無視されますか?
これはPython 3.3の新しい機能です(コメントノートとして、3.2では動作しません)。ジェネレーターのreturn
は、長い間raise StopIteration()
と同等でしたが、ジェネレーターのreturn <something>
はraise StopIteration(<something>)
と同等になりました。そのため、表示されている例外はStopIteration: 3
として出力される必要があり、値は例外のvalue
属性からアクセスできますオブジェクト:(新しい)yield from
構文を使用するようにジェネレーターが委任されている場合、それが結果になります詳細については、 PEP 38 を参照してください。
def f():
return 1
yield 2
def g():
x = yield from f()
print(x)
# g is still a generator so we need to iterate to run it:
for _ in g():
pass
これは1
を出力しますが、2
は出力しません。
戻り値は無視されませんが、ジェネレーターのみyield values、return
はジェネレーターを終了します。この場合は早期に終了します。その場合、ジェネレータを進めることはyield
ステートメントに決して到達しません。
イテレータが値の「終わり」に達して生成するたびに、StopIteration
mustが発生します。ジェネレーターも例外ではありません。 Python 3.3以降、return
式は例外の値になります。
_>>> def gen():
... return 3
... yield 2
...
>>> try:
... next(gen())
... except StopIteration as ex:
... e = ex
...
>>> e
StopIteration(3,)
>>> e.value
3
_
next()
を直接呼び出すのではなく、.__next__()
関数を使用して反復子を進めます。
_print(next(x))
_
この答えは質問とはまったく関係ありませんが、ウェブ検索後にここにたどり着く人にとっては役に立つかもしれません。
最終的な戻り値を生成値に変換する小さなヘルパー関数を次に示します。
def generator():
yield 1
yield 2
return 3
def yield_all(gen):
while True:
try:
yield next(gen)
except StopIteration as e:
yield e.value
break
print([i for i in yield_all(generator())])
[1、2、3]
またはデコレーターとして:
import functools
def yield_all(func):
gen = func()
@functools.wraps(func)
def wrapper():
while True:
try:
yield next(gen)
except StopIteration as e:
yield e.value
break
return wrapper
@yield_all
def a():
yield 1
yield 2
return 3
print([i for i in a()])
[1、2、3]