Pythonic方式循环纯粹基于副作用的理解

时间:2015-08-31 08:39:25

标签: python generator list-comprehension

执行完整生成器理解的最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)

然而,对于那些没有看到这种模式的人来说,并不是很明显。有没有更好的方法来循环完全理解而不保留内存中的所有返回值?

4 个答案:

答案 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)

在你的情况下nNone,所以:

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)

正如其他人所说,不要仅仅因为副作用而使用理解。

这是使用itertoolspartition()食谱执行您实际尝试的方式的好方法:

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]