使用列表推导仅仅是副作用是Pythonic吗?

sin*_*nan 97 python list-comprehension

想想我正在调用它的副作用的函数,而不是返回值(比如打印到屏幕,更新GUI,打印到文件等).

def fun_with_side_effects(x):
    ...side effects...
    return y
Run Code Online (Sandbox Code Playgroud)

现在,是Pythonic使用列表推导来调用这个函数:

[fun_with_side_effects(x) for x in y if (...conditions...)]
Run Code Online (Sandbox Code Playgroud)

请注意,我不会将列表保存在任何位置

或者我应该像这样调用这个函数:

for x in y:
    if (...conditions...):
        fun_with_side_effects(x)
Run Code Online (Sandbox Code Playgroud)

哪个更好?为什么?

Ign*_*ams 76

这样做非常反Pythonic,任何经验丰富的Pythonista都会给你带来地狱般的痛苦.中间列表在创建后会被丢弃,并且可能非常非常大,因此创建起来很昂贵.

  • 那个没有列出名单的人; 即第二种方式的一些变体(我已经知道在`for`之前使用genex来摆脱`if`). (6认同)
  • @Joachim Sauer:上面的例子2.一个正确的,显式的,非列表理解循环.明确.明确.明显. (5认同)
  • 那么什么是更加pythonic的方式? (4认同)

Kat*_*iel 30

你不应该使用列表理解,因为正如人们所说,将构建一个你不需要的大型临时列表.以下两种方法是等效的:

consume(side_effects(x) for x in xs)

for x in xs:
    side_effects(x)
Run Code Online (Sandbox Code Playgroud)

consumeitertools手册页的定义:

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)
Run Code Online (Sandbox Code Playgroud)

当然,后者更清晰,更容易理解.

  • 不确定这是特别惯用的.使用显式循环没有任何优势. (3认同)

Ikk*_*kke 20

列表推导用于创建列表.除非您实际创建列表,否则不应使用列表推导.

所以我会得到第二个选项,只是迭代列表,然后在条件适用时调用函数.

  • 我会更进一步说明列表理解中的副作用是不寻常的,意外的,因此是邪恶的,即使你在完成后使用结果列表. (4认同)

use*_*419 11

第二是更好.

想想需要理解代码的人.你可以轻松获得第一个恶误的业力:)

你可以使用filter()在两者之间中间.考虑这个例子:

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)
Run Code Online (Sandbox Code Playgroud)

  • 你的lambda更好地写成`lambda x:x> 3`. (10认同)
  • -1:不可读和(非常不重要)效率低下. (2认同)