使用列表parsing只是副作用是Pythonic?
想想一个函数,我叫它的副作用,而不是返回值(如打印到屏幕,更新GUI,打印到文件等)。
def fun_with_side_effects(x): ...side effects... return y
现在,使用列表parsing来调用这个func是Pythonic :
[fun_with_side_effects(x) for x in y if (...conditions...)]
请注意,我不保存在任何地方的列表
或者我应该这样称呼这个func:
for x in y: if (...conditions...): fun_with_side_effects(x)
哪个更好?为什么?
这样做是非常反Pythonic,任何经验丰富的python会给你一个地狱。 中间列表在创build后会被丢弃,并且可能非常大,因此创build起来很昂贵。
你不应该使用列表理解,因为正如人们所说,会build立一个你不需要的大型临时列表。 以下两种方法是等价的:
consume(side_effects(x) for x in xs) for x in xs: side_effects(x)
在itertools
手册页中定义了consume
:
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)
当然,后者更容易理解。
列表parsing是为了创build列表。 除非你真的创build一个列表,你不应该使用列表parsing。
所以我会得到第二个选项,只是迭代列表,然后调用条件适用时的函数。
其次是更好。
想想那些需要了解你的代码的人。 你可以轻松得到不好的业力与第一:)
你可以通过使用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)
取决于你的目标。
如果您正在尝试对列表中的每个对象执行一些操作,则应采用第二种方法。
如果您正尝试从另一个列表中生成列表,则可以使用列表理解。
显式比隐式更好。 简单胜于复杂。 (Python禅)
你可以做
for z in (fun_with_side_effects(x) for x in y if (...conditions...)): pass
但不是很漂亮
我会这样做:
any(fun_with_side_effects(x) and False for x in y if (...conditions...))
这是一个生成器expression式,并不会生成一个随机列表被抛出。 我认为这是丑陋的,我不会在代码中做到这一点。 但是如果你坚持以这种方式实现你的循环,那就是我该怎么做的。
我倾向于认为列表理解及其同类应该表明尝试使用至less微不足道的function风格的东西。 把那些违背这个假设的副作用放在一起会让人们更仔细地阅读你的代码,我认为这是一件坏事。