具有可变数量元素的附加解包概括(PEP 448)

Additional Unpacking Generalizations (PEP 448) with variable number of elements

接受 PEP 448Python 3.5.

例如:

>>> l1 = [1, 2, 3]
>>> l2 = [4, 5, 6]

# unpack both iterables in a list literal
>>> joinedList = [*l1, *l2]
>>> print(joinedList)
[1, 2, 3, 4, 5, 6]

问题:有没有办法对列表的列表做类似的事情?

此代码无效:

SyntaxError: iterable unpacking cannot be used in comprehension

# List of variable size
list_of_lists = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
joined_list = [*l for l in list_of_lists]

当然,您可以执行以下操作,但看起来不太优雅且效率不高:

# List of variable size
list_of_lists = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
joined_list = list()
for l in list_of_lists:
    joined_list += l

老派怎么样:sum()

代码:

joined_list = sum(list_of_lists, [])

测试代码:

# List of variable size
list_of_lists = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
joined_list = sum(list_of_lists, [])
print(joined_list)

结果:

[1, 2, 3, 4, 5, 6, 7, 8, 9]

我不鼓励在这里使用 sum,因为它是 Schlemiel the Painter's algorithm 的一种形式。 sum 实际上用 str 禁止它;他们并没有尝试阻止所有序列使用以避免放慢速度 sum 试图阻止每一次滥用,但这仍然是一个坏主意。

问题在于,这意味着您每次构建逐渐变大的临时 lists,通过复制 所有内容 构建下一个临时文件后丢弃最后一个临时文件到目前为止,我一遍又一遍地看到新东西。如果第一个列表中有一百万个项目,并且您还有十个 list 可以连接到它上面,那么您将复制至少一千万个元素(即使其他十个 list 是空的).您的原始代码实际上更好,因为使用 += 运算符执行就地扩展,在 O(n) 中保持最坏情况的性能(对于所有 list 中的 n 元素s) 范围,而不是 O(n*m)(对于 m lists 中的 n 个元素)。

它也有只对一种一致的类型起作用的问题;如果一些输入是 lists,一些是 tuples 和一些生成器,sum 将不起作用(因为 list.__add__ 不会接受非 list另一边的操作数)。

所以不要那样做。这是 what itertools.chain and it's alternate constructor, itertools.chain.from_iterable were made for:

from itertools import chain

list_of_lists = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
joined_list = list(chain.from_iterable(list_of_lists))

它是有保证的 O(n),可以与你向它抛出的任何迭代一起工作,等等。

是的,很明显,如果你只得到三个 list 的三个元素,这并不重要。但是,如果输入可迭代对象的大小或可迭代对象的数量任意大,或者类型不一致,chain 会起作用,sum 不会。