空のジェネレータ関数を定義するにはどうすればいいですか? 質問する

空のジェネレータ関数を定義するにはどうすればいいですか? 質問する

ジェネレータ関数は、yield関数本体にキーワードを配置することで定義できます。

def gen():
    for i in range(10):
        yield i

空のジェネレータ関数を定義するにはどうすればいいですか?

次のコードは、Python が通常の関数ではなくジェネレーター関数であることを認識できないため、機能しません。

def empty():
    pass

次のようなことができます:

def empty():
    if False:
        yield

しかし、それは非常に醜いでしょう。もっと良い方法はあるでしょうか?

ベストアンサー1

returnジェネレーターで once を使用できます。これは、何も生成せずに反復を停止し、関数をスコープ外で実行することに対する明示的な代替手段を提供します。したがってyield、関数をジェネレーターに変換するには を使用しますが、その前に を付けて、return何も生成する前にジェネレーターを終了します。

>>> def f():
...     return
...     yield
... 
>>> list(f())
[]

これがあなたのものよりはるかに優れているかどうかはわかりません。これは単に no-opifステートメントを no-op ステートメントに置き換えるだけです。しかし、より慣用的です。ただ using だけでは機能しないyieldことに注意してください。yield

>>> def f():
...     yield
... 
>>> list(f())
[None]

を単に使用しないのはなぜですかiter(())?

この質問は特に空のジェネレータ関数そのため、私はこれを、一般的な空のイテレータを作成するための最良の方法に関する質問ではなく、Python の構文の内部一貫性に関する質問であると考えています。

質問が実際に空のイテレータを作成する最良の方法についてのものであれば、あなたは同意するかもしれませんゼクトブモ代わりにを使うことについてiter(())。しかし、 は関数を返さないことに注意することが重要ですiter(())。 空の反復可能オブジェクトを直接返します。呼び出し可能なオブジェクトを期待するAPIを扱っているとします。戻り値通常のジェネレータ関数と同様に、呼び出されるたびに反復可能になります。次のようにする必要があります。

def empty():
    return iter(())

(クレジットはウヌトブこの回答の最初の正しいバージョンをくれた方に感謝します。

さて、上記はより明確になったと思うかもしれませんが、明確でない状況も想像できます。(不自然な)ジェネレータ関数定義の長いリストの例を考えてみましょう。

def zeros():
    while True:
        yield 0

def ones():
    while True:
        yield 1

...

その長いリストの最後には、次のような が含まれるものが見たいですyield

def empty():
    return
    yield

または、Python 3.3以降(ドイツ)、 これ:

def empty():
    yield from ()

キーワードの存在によりyield、これは他のジェネレーター関数とまったく同じであることが一目瞭然です。 このiter(())バージョンが同じことを実行していることがわかるまでには、もう少し時間がかかります。

微妙な違いですが、正直なところ、yieldベースの関数の方が読みやすく、保守しやすいと思います。

この素晴らしい回答もご覧くださいユーザー3840170これは、disこのアプローチが望ましいもう 1 つの理由を示しています。コンパイル時に生成される命令が最も少なくなるためです。

おすすめ記事