web-dev-qa-db-ja.com

副作用だけのためにリスト内包表記を使用するのはPythonicですか?

戻り値ではなく、副作用として求めている関数について考えてください(画面への出力、GUIの更新、ファイルへの出力など)。

def fun_with_side_effects(x):
    ...side effects...
    return y

さて、それはPythonicリスト内包表記を使用してこの関数を呼び出すことです:

[fun_with_side_effects(x) for x in y if (...conditions...)]

リストをどこにも保存しないことに注意してください

または、このfuncを次のように呼び出す必要があります。

for x in y:
    if (...conditions...):
        fun_with_side_effects(x)

どちらがより良いのですか、なぜですか?

101
sinan

そうすることは非常に反Pythonicであり、ベテランのPythonistaはあなたに地獄を与えるでしょう。中間リストは作成後に破棄されるため、非常に大きくなる可能性があり、作成に費用がかかる可能性があります。

list内包表記は使用しないでください。これは、人々が言っ​​ているように、不要な大きな一時リストを作成するためです。次の2つの方法は同等です。

consume(side_effects(x) for x in xs)

for x in xs:
    side_effects(x)

consume manページのitertoolsの定義を使用:

def consume(iterator, n=None):
    "Advance the iterator n-steps ahead. If n is none, consume entirely."
    # Use functions that consume iterators at C speed.
    if n is None:
        # feed the entire iterator into a zero-length deque
        collections.deque(iterator, maxlen=0)
    else:
        # advance to the empty slice starting at position n
        next(islice(iterator, n, n), None)

もちろん、後者の方が明確で理解しやすいです。

31
Katriel

リスト内包表記は、リストを作成するためのものです。そして、実際にリストを作成しているのでない限り、notリスト内包表記を使用する必要があります。

だから私は2番目のオプションを得るために、リストを反復し、条件が適用されたときに関数を呼び出します。

20
Ikke

二番目は良いです。

あなたのコードを理解する必要がある人を考えてください。あなたは最初の:)で簡単に悪いカルマを得ることができます

Filter()を使用して、2つの中間に行くことができます。例を考えてみましょう:

y=[1,2,3,4,5,6]
def func(x):
    print "call with %r"%x

for x in filter(lambda x: x>3, y):
    func(x)
11
user237419

あなたの目標に依存します。

リスト内の各オブジェクトに対して何らかの操作を実行しようとしている場合は、2番目のアプローチを採用する必要があります。

別のリストからリストを生成しようとしている場合は、リスト内包表記を使用できます。

明示的は暗黙的よりも優れています。シンプルは複雑よりも優れています。 (Python Zen)

3
rubayeet

できるよ

for z in (fun_with_side_effects(x) for x in y if (...conditions...)): pass

しかし、それは非常にきれいではありません。

0
sigs