执行完整生成器理解的最pythonic方法是什么,你不关心返回值,而操作纯粹是基于副作用的?
一个例子是根据讨论的here基于谓词值拆分列表。想到编写生成器理解是很自然的
split_me = [0, 1, 2, None, 3, '']
a, b = [], []
gen_comp = (a.append(v) if v else b.append(v) for v in split_me)
在这种情况下,我能想出的最佳解决方案是使用any
any(gen_comp)
然而,对于那些没有看到这种模式的人来说,并不是很明显。有没有更好的方法来循环完全理解而不保留内存中的所有返回值?
答案 0 :(得分:5)
您可以通过不使用生成器表达式来实现。
只需写一个合适的循环:
for v in split_me:
if v:
a.append(v)
else:
b.append(v)
或者也许:
for v in split_me:
target = a if v else b
target.append(v)
如果要立即执行生成器 ,则使用生成器表达式毫无意义。当你想要的只是将值附加到另外两个列表时,为什么要生成一个对象加上一系列None
返回值?
使用显式循环对于代码的未来维护者(包括您)更加易于理解,并且更有效。
答案 1 :(得分:3)
itertools
有这个消耗食谱
def consume(iterator, n):
"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)
在你的情况下n
是None
,所以:
collections.deque(iterator, maxlen=0)
这很有意思,但也有很多机器可以完成一项简单的任务
大多数人只会使用for
循环
答案 2 :(得分:3)
在多行编写内容并使用for v in split_me:
if v:
a.append(v)
else:
b.append(v)
语句时,没有任何非pythonic语句:
for v in split_me: a.append(v) if v else b.append(v)
如果你想要一个单行程,你可以通过将循环放在一行来实现:
[x for x in (a.append(v) if v else b.append(v) for v in split_me) if False]
如果你想要它在一个表达式中(除非你有一个你希望得到的值,你仍然想要为什么你想要它)你可以使用list comprehension来强制循环:
http://docs.meteor.com/#/full/mongo_collection
您认为哪种解决方案最能说明您正在做什么?我会说第一个解决方案。要成为pythonic你应该考虑zen of python,尤其是:
答案 3 :(得分:3)
正如其他人所说,不要仅仅因为副作用而使用理解。
这是使用itertools
中partition()
食谱执行您实际尝试的方式的好方法:
try: # Python 3
from itertools import filterfalse
except ImportError: # Python 2
from itertools import ifilterfalse as filterfalse
from itertools import ifilter as filter
from itertools import tee
def partition(pred, iterable):
'Use a predicate to partition entries into false entries and true entries'
# From itertools recipes:
# https://docs.python.org/3/library/itertools.html#itertools-recipes
# partition(is_odd, range(10)) --> 0 2 4 6 8 and 1 3 5 7 9
t1, t2 = tee(iterable)
return filterfalse(pred, t1), filter(pred, t2)
split_me = [0, 1, 2, None, 3, '']
trueish, falseish = partition(lambda x: x, split_me)
# You can iterate directly over trueish and falseish,
# or you can put them into lists
trueish_list = list(trueish)
falseish_list = list(falseish)
print(trueish_list)
print(falseish_list)
输出:
[0, None, '']
[1, 2, 3]