[解決済み] Python: ジェネレータ式とyieldの比較
質問
Pythonでは、ジェネレータオブジェクトを ジェネレータ式 を使うのと 降伏 ステートメントを使うか?
使用方法 降伏 :
def Generator(x, y):
for i in xrange(x):
for j in xrange(y):
yield(i, j)
使用方法 ジェネレータ式 :
def Generator(x, y):
return ((i, j) for i in xrange(x) for j in xrange(y))
どちらの関数も、(0,0)、(0,1)などのタプルを生成するジェネレータオブジェクトを返します。
どちらか一方の利点はありますか?感想は?
どのように解決するのですか?
両者にはわずかな違いしかありません。 あなたは
dis
モジュールを使って、自分でこの種のことを調べることができます。
編集してください。 私の最初のバージョンは、対話型プロンプトのmodule-scopeで作成されたジェネレータ式をデコンパイルしました。 これは、関数内で使用されているOPのバージョンとは若干異なります。 質問の実際のケースと一致するようにこれを修正しました。
下記でわかるように、"yield"ジェネレータ(最初のケース)にはセットアップで3つの余分な命令がありますが、1番目から
FOR_ITER
を使用します。
LOAD_FAST
の代わりに
LOAD_DEREF
に置き換えます。 その
LOAD_DEREF
は
"むしろ遅くなる"。
よりも
LOAD_FAST
の値が十分に大きい場合、ジェネレータ式よりも "yield"版の方がわずかに速くなります。
x
(外側ループ) の値は
y
の値は各パスでわずかに速くロードされるからです。 より小さい値の
x
の値が小さい場合は、設定コードのオーバーヘッドが増えるため、わずかに遅くなります。
ジェネレータ式は通常、関数でラップするのではなく、コード内でインラインで使用されることを指摘する価値があるかもしれません。 これにより、セットアップのオーバーヘッドを少し取り除き、ループ値が小さい場合にジェネレータ式をわずかに高速に保つことができます。
LOAD_FAST
が "yield" 版を優位に立たせたとしても、より小さなループ値ではジェネレーター式がわずかに速く保たれます。
どちらの場合も、パフォーマンスの違いは、どちらか一方を選択することを正当化するのに十分なものではありません。 読みやすさの方がはるかに重要なので、その時の状況に応じて、最も読みやすいと感じる方を使用してください。
>>> def Generator(x, y):
... for i in xrange(x):
... for j in xrange(y):
... yield(i, j)
...
>>> dis.dis(Generator)
2 0 SETUP_LOOP 54 (to 57)
3 LOAD_GLOBAL 0 (xrange)
6 LOAD_FAST 0 (x)
9 CALL_FUNCTION 1
12 GET_ITER
>> 13 FOR_ITER 40 (to 56)
16 STORE_FAST 2 (i)
3 19 SETUP_LOOP 31 (to 53)
22 LOAD_GLOBAL 0 (xrange)
25 LOAD_FAST 1 (y)
28 CALL_FUNCTION 1
31 GET_ITER
>> 32 FOR_ITER 17 (to 52)
35 STORE_FAST 3 (j)
4 38 LOAD_FAST 2 (i)
41 LOAD_FAST 3 (j)
44 BUILD_TUPLE 2
47 YIELD_VALUE
48 POP_TOP
49 JUMP_ABSOLUTE 32
>> 52 POP_BLOCK
>> 53 JUMP_ABSOLUTE 13
>> 56 POP_BLOCK
>> 57 LOAD_CONST 0 (None)
60 RETURN_VALUE
>>> def Generator_expr(x, y):
... return ((i, j) for i in xrange(x) for j in xrange(y))
...
>>> dis.dis(Generator_expr.func_code.co_consts[1])
2 0 SETUP_LOOP 47 (to 50)
3 LOAD_FAST 0 (.0)
>> 6 FOR_ITER 40 (to 49)
9 STORE_FAST 1 (i)
12 SETUP_LOOP 31 (to 46)
15 LOAD_GLOBAL 0 (xrange)
18 LOAD_DEREF 0 (y)
21 CALL_FUNCTION 1
24 GET_ITER
>> 25 FOR_ITER 17 (to 45)
28 STORE_FAST 2 (j)
31 LOAD_FAST 1 (i)
34 LOAD_FAST 2 (j)
37 BUILD_TUPLE 2
40 YIELD_VALUE
41 POP_TOP
42 JUMP_ABSOLUTE 25
>> 45 POP_BLOCK
>> 46 JUMP_ABSOLUTE 6
>> 49 POP_BLOCK
>> 50 LOAD_CONST 0 (None)
53 RETURN_VALUE
関連
-
[解決済み] Pythonには文字列の'contains'サブストリングメソッドがありますか?
-
[解決済み] Pythonで現在時刻を取得する方法
-
[解決済み] Pythonで2つのリストを連結する方法は?
-
[解決済み] Python 3で「1000000000000000 in range(1000000000000001)」はなぜ速いのですか?
-
[解決済み】Pythonに三項条件演算子はありますか?
-
[解決済み】2つの辞書を1つの式でマージする(辞書の和をとる)には?)
-
[解決済み] python-requests モジュールからのすべてのリクエストをログに記録します。
-
[解決済み] Jupyter (IPython)ノートブックのセッションをpickleして保存する方法
-
[解決済み] Django filter queryset __in for *every* item in list
-
[解決済み] Python の sorted() はどのようなアルゴリズムを使っているのですか?重複
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] Pythonのマルチプロセッシングプールimap_unorderedの呼び出しの進捗を表示しますか?
-
[解決済み] Pythonのインスタンス変数とクラス変数
-
[解決済み] 古いバージョンのPythonにおける辞書のキーの並び順
-
[解決済み] Pythonで0xを使わずにhex()を使うには?
-
[解決済み] 範囲指定された浮動小数点数のランダムな配列を生成します。
-
[解決済み] Django で全てのリクエストヘッダを取得するにはどうすれば良いですか?
-
[解決済み] Pythonの検索パスを他のソースに展開する
-
[解決済み] Pythonでファイルの読み込みと上書きをする
-
[解決済み] Django filter queryset __in for *every* item in list
-
[解決済み] Pythonでリストが空かどうかをチェックする方法は?重複