web-dev-qa-db-ja.com

同一の関数で返り、譲ります

このように、Pythonの同じ関数でyieldとreturnが使用された場合、正確にはどうなりますか?

def find_all(a_str, sub):
    start = 0
    while True:
        start = a_str.find(sub, start)
        if start == -1: return
        yield start
        start += len(sub) # use start += 1 to find overlapping matches

まだジェネレーターですか?

56
nekomimi

はい、それはまだジェネレータです。 returnは、(ほぼ)StopIterationを上げることと同等です。

PEP 255 綴り:

仕様:返品

ジェネレーター関数には、次の形式のreturnステートメントを含めることもできます。

"return"

Expression_listは、ジェネレーターの本体のreturnステートメントでは許可されないことに注意してください(もちろん、ジェネレーター内にネストされた非ジェネレーター関数の本体に表示される場合があります)。

Returnステートメントが検出されると、制御は任意の関数returnのように進み、適切なfinally節(存在する場合)を実行します。次に、StopIteration例外が発生し、反復子が使い果たされたことを通知します。 StopIteration例外は、明示的な戻りなしで制御がジェネレーターの端から流れた場合にも発生します。

ジェネレーター関数と非ジェネレーター関数の両方について、returnは「完了し、返すのに興味のあるものは何もない」という意味であることに注意してください。

Returnは必ずしもStopIterationを上げることと同じではないことに注意してください。違いは、囲むtry/exceptコンストラクトの処理方法にあります。例えば、

>>> def f1():
...     try:
...         return
...     except:
...        yield 1
>>> print list(f1())
[]

なぜなら、どの関数でもそうであるように、returnは単純に終了しますが、

>>> def f2():
...     try:
...         raise StopIteration
...     except:
...         yield 42
>>> print list(f2())
[42]

stopIterationは、例外と同様に、裸の「例外」によってキャプチャされるためです。

59
NPE

はい、それはまだジェネレータです。空のreturnまたはreturn Noneを使用して、ジェネレーター関数を終了できます。これは、StopIteration(詳細は @ NPEの答え を参照)を上げるのと同じです。

None以外の引数での戻り値は、3.3より前のバージョンPythonのSyntaxErrorです。

Python 3.3から始まるコメントで@BrenBarnが指摘したように、戻り値はStopIteration.に渡されるようになりました]

PEP 38 から:

ジェネレーターでは、ステートメント

return value

意味的に等価です

raise StopIteration(value)
24

値またはジェネレーターを返すことができる関数にyieldおよびreturnメソッドを設定する方法があります。

おそらくあなたが望むほどきれいではありませんが、期待どおりに動作します。

次に例を示します。

def six(how_many=None):
    if how_many is None or how_many < 1:
        return None  # returns value

    if how_many == 1:
        return 6  # returns value

    def iter_func():
        for count in range(how_many):
            yield 6
    return iter_func()  # returns generator
8
William Rusnack