ジェネレータは、レイジー評価そうですreturn
か、yield
あなたのコードをデバッグするか、例外がスローされた場合しているときに異なる動作をします。
return
あなたに起こるすべての例外generator
については何も知らないであろうgenerate_all
時にためだ、generator
本当に実行されますが、すでに残っているgenerate_all
機能を。yield
そこにそれがありますgenerate_all
トレースバックに。
def generator(some_list):
for i in some_list:
raise Exception('exception happened :-)')
yield i
def generate_all():
some_list = [1,2,3]
return generator(some_list)
for item in generate_all():
...
Exception Traceback (most recent call last)
<ipython-input-3-b19085eab3e1> in <module>
8 return generator(some_list)
9
---> 10 for item in generate_all():
11 ...
<ipython-input-3-b19085eab3e1> in generator(some_list)
1 def generator(some_list):
2 for i in some_list:
----> 3 raise Exception('exception happened :-)')
4 yield i
5
Exception: exception happened :-)
そしてそれが使用している場合yield from
:
def generate_all():
some_list = [1,2,3]
yield from generator(some_list)
for item in generate_all():
...
Exception Traceback (most recent call last)
<ipython-input-4-be322887df35> in <module>
8 yield from generator(some_list)
9
---> 10 for item in generate_all():
11 ...
<ipython-input-4-be322887df35> in generate_all()
6 def generate_all():
7 some_list = [1,2,3]
----> 8 yield from generator(some_list)
9
10 for item in generate_all():
<ipython-input-4-be322887df35> in generator(some_list)
1 def generator(some_list):
2 for i in some_list:
----> 3 raise Exception('exception happened :-)')
4 yield i
5
Exception: exception happened :-)
ただし、これはパフォーマンスを犠牲にします。追加のジェネレータ層には、ある程度のオーバーヘッドがあります。したがってreturn
、一般的にはyield from ...
(またはfor item in ...: yield item
)より少し高速になります。ほとんどの場合、これはそれほど重要ではありません。ジェネレーターで行うことは通常、ランタイムを支配するため、追加のレイヤーは目立たなくなります。
ただしyield
、追加の利点がいくつかあります。単一の反復可能オブジェクトに制限されず、追加の項目を簡単に生成することもできます。
def generator(some_list):
for i in some_list:
yield i
def generate_all():
some_list = [1,2,3]
yield 'start'
yield from generator(some_list)
yield 'end'
for item in generate_all():
print(item)
start
1
2
3
end
あなたの場合、操作は非常に簡単で、これのために複数の関数を作成する必要があるかどうかはわかりませんが、map
代わりに組み込み式またはジェネレータ式を簡単に使用できます:
map(do_something, get_the_list()) # map
(do_something(i) for i in get_the_list()) # generator expression
どちらも使用するために(例外が発生したときのいくつかの違いを除いて)同一である必要があります。また、よりわかりやすい名前が必要な場合でも、それらを1つの関数でラップできます。
組み込みの反復可能オブジェクトに対する非常に一般的な操作をラップするヘルパーが複数あり、さらに他のヘルパーは組み込みitertools
モジュールにあります。そのような単純なケースでは、私は単にこれらに頼り、自明でないケースでのみ独自のジェネレーターを作成します。
しかし、私はあなたの実際のコードがより複雑であるために適用できないかもしれないと思いますが、私はそれが代替案に言及することなしに完全な答えではないと思いました。