web-dev-qa-db-ja.com

python:lambda、yield-statement / expressionおよびloops(明確化)

TLDR:yield内にlambdaまたはジェネレーターステートメント(ループ付き)を実装できますか?

私の質問は明確にすることです:

以下の単純なループ関数をyieldで実装できるかどうか

def loopyield():
   for x in range(0,15):
      yield x
print(*loopyield())

エラーの結果:

lamyield=lambda x: yield x for x in range(0,15)
                       ^
SyntaxError: invalid syntax

どのように見えますか?それは、書かれていないreturnステートメントの正しいオペランドとして何かを期待していましたが、yeildを見つけて混乱しました。

ループでこれを達成するための適切な合法はありますか?

サイドノート:yieldは、あなたが尋ねる人に応じてステートメント/式になります: yield-statement or expression?

最終回答:yieldはlambdaで使用できますが、制限(単一行)が役に立たなくなります。 for/whileは式ではないため、ラムダでは不可能です。 -user2357112暗黙のforループはリスト内包表記で可能であり、yieldはリスト内包内で有効です。 -wim

判定-pythonのラムダには式のみを含めることができるため、明示的なループを記述するために、明示的なループは不可能です。ステートメントを使用する必要があります-wim

19
theMobDog

あなたが作成しようとしているワンライナーは、実際にはラムダで技術的に可能です、あなたはもう少しパーサーを助ける必要があります:

>>> lamyield = lambda: [(yield x) for x in range(15)]
>>> print(*lamyield())
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14

これは、リスト内包で暗黙的にforループを使用します。明示的なwhileループまたは内包の外側のforループでは不可能です。 pythonのラムダには expressions のみを含めることができ、明示的なループを記述するには statements を使用する必要があるためです。

注:この構文はPython 3.7で非推奨になり、Python 3.8SyntaxErrorが発生します

25
wim

yieldの内部でlambdaを使用する必要はありますか。

In[1]: x = (i for i in range(15))
In[2]: x
Out[2]: <generator object <genexpr> at 0x7fbdc69c3f10>

In[3]: print(*x)
Out[3]: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14

In[4]: x = (i for i in range(0, 15))
In[5]: x.__next__()
Out[5]: 0

In[6]: next(x)
Out[6]: 1
5
N.C.

実際には、ラムダを便利な方法でループすることができます。あなたが提供した例が素晴らしいユースケースではないというだけです。

yield内でlambdaを使用する場合の1つの例は、必要な場合にのみ高価な関数を遅延実行することです。そのようです:

for check, args in (lambda: (
                            (yield (expensive_check1(), ["foo", "bar"])), 
                            (yield (expensive_check2(), ["baz"])),
                            (yield (expensive_check3(), []), [])),
                    ))():
    if check:
        x = do_the_thing(*args)
        break
else:
    raise Exception("oh noes!!!")

*この構文は、内包表記の中でyieldを使用していないため、Python 3.8でも動作します。

1
Rick Teachey