1. ホーム
  2. python

[解決済み] Python Empty Generator 関数

2022-07-21 09:55:55

質問

Pythonでは、yieldキーワードを関数本体に記述することで、以下のように簡単にイテレータ関数を定義することができます。

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

どのようにすれば、値を生成しない(0値を生成する)ジェネレータ関数を定義できますか。以下のコードは、パイソンが通常の関数ではなくジェネレータであることを認識できないため、動作しません。

def empty():
    pass

のようなことができる。

def empty():
    if False:
        yield None

しかし、それは非常に醜いでしょう。空のイテレータ関数を実現するいい方法はないでしょうか?

どのように解決するのですか?

この場合 return これは何も得ずに反復を停止させるので、関数をスコープ外に出すことのない明示的な代替手段を提供します。そのため yield を使って関数をジェネレータに変えますが、その前に return を付けてジェネレータを終了させます。

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

を置き換えるだけなので、今あるものよりずっといいとは思えません。 if ステートメントを省略のない yield ステートメントを使用します。しかし、その方がよりイディオム的です。なお、単に yield を使うだけではうまくいかないことに注意してください。

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

なぜ iter(()) ?

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

もし質問が実際に空のイテレータを作成する最良の方法についてのものであるなら、あなたは以下の意見に同意するかもしれません。 Zectbumo を使うことについては iter(()) を使うことにしました。しかし、重要なのは iter(()) は関数を返さないということです。これは直接、空の反復処理可能ファイルを返します。という callable を期待する API で作業しているとします。 を返す を返す呼び出し可能な 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以上では(提案されているように) DSM によって提案されている)、これです。

def empty():
    yield from ()

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

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

この素晴らしい回答もご覧ください。 ユーザー3840170 を使用した dis を使って、この方法が望ましいもう一つの理由を示しています。それは、コンパイル時に最も少ない命令数で済むということです。