web-dev-qa-db-ja.com

Python空のジェネレーター関数

Pythonでは、次のようなyieldキーワードを関数の本体に挿入することで、反復関数を簡単に定義できます。

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

値を生成しない(値0を生成する)ジェネレーター関数を定義するには、pythonが通常の関数ではなくジェネレーターであることを認識できないため、次のコードは機能しません。

def empty():
    pass

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

def empty():
    if False:
        yield None

しかし、それは非常にいものです。空のイテレータ関数を実現する良い方法はありますか?

80

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

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

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

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

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

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

質問が実際に空のイテレータを作成する最良の方法についてである場合、代わりにiter(())を使用することについて Zectbumo に同意するかもしれません。ただし、iter(())は関数を返さないことに注意してください。空のイテラブルを直接返します。 returnsiterableであるcallableを期待するAPIで作業しているとします。次のようなことをする必要があります。

_def empty():
    return iter(())
_

(クレジットは、この回答の最初の正しいバージョンを提供するために nutb に移動する必要があります。)

今、あなたは上記をより明確にするかもしれませんが、私はそれがあまり明確でない状況を想像することができます。 (作成された)ジェネレーター関数定義の長いリストのこの例を考えてみましょう:

_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ベースの関数はより読みやすく保守しやすいと思います。

105
senderle
iter(())

必須ジェネレーターではありません。おいおい!

63
Zectbumo

Python 3.3(私は_yield from_キックをしているので、@ senderleは私の最初の考えを盗んだからです):

_>>> def f():
...     yield from ()
... 
>>> list(f())
[]
_

ただし、iter([])または_(x)range(0)_が同様にうまく機能しないこのユースケースを考え出すのに苦労しています。

45
DSM

別のオプションは次のとおりです。

(_ for _ in ())
13
Ben Reynwar

私は次を好む:

def foo():
  raise StopIteration()
  yield

「yield」はジェネレータに変換し、ExceptionはNoneが結果に含まれないことを意味します(純粋に空の結果)。

6
eddiewould

ジェネレーター関数でなければなりませんか?そうでない場合はどうですか

def f():
    return iter([])
4
unutbu

空のイテレータを作成する「標準的な」方法は、iter([])のようです。 []をiter()のデフォルト引数にすることを提案しました。これは適切な引数で拒否されました。 http://bugs.python.org/issue25215 を参照してください-Jurjen

3
Jurjen Bos

実際に関数を必要とし、実際にジェネレータを必要とするあなたのために

empty = lambda: (_ for _ in ())
0
Zectbumo
generator = (item for item in [])
0
user2113422