2016-08-06 13 views
1

以下は、私のコードの簡単な例です。forループの代わりに補題を使用する

>>> def action(num): 
     print "Number is", num 
>>> items = [1, 3, 6] 
>>> for i in [j for j in items if j > 4]: 
     action(i) 
Number is 6 

私の質問は以下の通りです:は、単にまだaction関数を呼び出します理解してforループを交換する(このようなコードの明確さなどの理由で)悪い習慣ですか?つまり:

>>> (action(j) for j in items if j > 2) 
Number is 6 
+0

アクションは何も返されないので、最初はリストとそれ以上のループを作成していないので、実際にはもっと素敵で速いですリストコンプのために '[]'を使います。 –

+0

これは実際にあなたがそこに持っているジェネリックステートメントであり、リストの解説ではありません。私はそれがあなたの質問に重大な影響を与えるかどうかはわかりません。 – Tagc

+0

@Tagcジェネレータを作成することは分かっていますが、それをジェネレータの理解と呼んでいるかどうかは分かりませんでしたが、リストの理解のために同じ考えをしています。何らかの理由で他よりも優先されるのでしょうか? – Siwel

答えて

4

これは、発電機または理解度を全く使用しないでください。

def action(num): 
    print "Number is", num 

items = [1, 3, 6] 
for j in items: 
    if j > 4: 
     action(i) 

ジェネレータは遅延して評価されます。式(action(j) for j in items if j > 2)は単にジェネレータ式を呼び出し側に返します。あなたが明示的にそれを使い切っていない限り、何も起こりません。リスト内包表記は熱心に評価されますが、この特定のケースでは、目的のないlistが残ります。ちょうど通常のループを使用してください。

+0

"リスト内包は熱心に評価されますが、この特定のケースでは目的のないリストが残っています。 " 他の人が良い点を挙げていますが、これはジェネレータ表現/リスト内包表記を使用した場合の非常に強力な議論です。私はこの回答のために私のupvoteのチップに行くつもりです。 – Tagc

+0

「目的なしに」リストを作成することは、特に悪い考えですか?もちろん、@Siwel。 – Siwel

+1

。何も必要ない場合は、作成しないでください!したがって、読みやすさとコード実行のスピードが向上します。 –

1

私は個人的にはTigerhawk's solutionですが、彼とwillywonkadailyblahの解決策(今削除されています)の中間になるかもしれません。

willywonkadailyblahのポイントの1つであった:

なぜだけではなく、古いものを使用しての新しいリストを作成しますか?あなたはすでに正しい要素を除外するための条件を持っています。なぜそれらをメモリに入れて戻すのですか?

この問題を回避する1つの方法、すなわちフィルタリングはジェネレータ式のフィルタリング一部ではなく、リスト内包することによって、ループのために使用した反復処理する場合にのみ行っているフィルタリングの遅延評価を使用することです。

すべての正直で出力

Number is 6 

for i in (j for j in items if j > 4): 
    action(i) 

、私はTigerhawを考えますしかし、kの解がこれには最高です。これはただ一つの可能​​な選択肢です。

私が提案した理由は、C#でLINQクエリを思い出させるため、1つのステートメント(LINQ式)内のシーケンスから要素を抽出、フィルタリング、投影するという怠惰な方法を定義し、そのクエリーで別のfor eachループを使用して、各要素に対して何らかのアクションを実行します。

1

これは悪い習慣です。第1に、あなたのコード断片は、望ましい出力を生成しません。代わりに、<generator object <genexpr> at 0x03D826F0>のようなものが得られます。

第2に、リストの理解はシーケンスを作成するためであり、ジェネレータaはオブジェクトのストリームを作成するためです。典型的には、副作用はない。あなたのアクション関数は、副作用の主要な例です。それは入力を出力し、何も返しません。むしろ、ジェネレータは生成する各アイテムに対して、入力を取り、出力を計算する必要があります。例えば。あなたがグローバル状態(何かを印刷する)を変異させ、およびオブジェクトのストリームを作成することはなく、あなたのコードの目的は、難読化されている発電機を使用することにより

doubled_odds = [x*2 for x in range(10) if x % 2 != 0] 

。 一方、forループを使用するだけで、コードはわずかに長くなります(基本的には空白になります)。しかし、すぐに目的は(アイテムの新しいストリーム/リストを作成するのではなく)アイテムを選択して、 。

for i in items: 
    if i < 4: 
     action(i) 

発電機はまだループ構造、基礎となるバイトコードが同じ多かれ少なかれあること(どちらかといえば、発電機はわずかに効率が低い)、あなたは明快さを失うされていることに注意してください。ジェネレータとリスト内包はすばらしいですが、これは正しい状況ではありません。

関連する問題