函数调用中的星号

135 投票
3 回答
58666 浏览
提问于 2025-04-16 13:18

我正在使用 itertools.chain 来把一个列表中的列表“扁平化”,也就是把里面的内容合并成一个单一的列表,像这样:

uniqueCrossTabs = list(itertools.chain(*uniqueCrossTabs))

这和说:

uniqueCrossTabs = list(itertools.chain(uniqueCrossTabs))

3 个回答

32

这只是另一种解释这个概念或使用它的方法。

import random

def arbitrary():
    return [x for x in range(1, random.randint(3,10))]

a, b, *rest = arbitrary()

# a = 1
# b = 2
# rest = [3,4,5]
83

它把这个序列分成了多个单独的参数,用于函数调用。

>>> def foo(a, b=None, c=None):
...   print a, b, c
... 
>>> foo([1, 2, 3])
[1, 2, 3] None None
>>> foo(*[1, 2, 3])
1 2 3
>>> def bar(*a):
...   print a
... 
>>> bar([1, 2, 3])
([1, 2, 3],)
>>> bar(*[1, 2, 3])
(1, 2, 3)
206

* 是一个叫做 "splat" 的操作符:它可以把像列表这样的可迭代对象作为输入,然后把它展开成实际的参数,传递给函数。

比如说,如果 uniqueCrossTabs[[1, 2], [3, 4]],那么 itertools.chain(*uniqueCrossTabs) 就相当于 itertools.chain([1, 2], [3, 4])

这和直接传入 uniqueCrossTabs 是不一样的。你这里有一个包含多个列表的列表,你想把它们“扁平化”;而 itertools.chain() 的作用是返回一个迭代器,这个迭代器会把你传入的所有参数连接在一起,每个参数本身也是一个可迭代的对象。

换句话说,你想把 uniqueCrossTabs 中的每个列表作为参数传给 chain(),这样它就能把这些列表连接在一起。但因为你没有把这些列表放在单独的变量里,所以你使用 * 操作符来把这个列表的列表展开成多个列表参数。

chain.from_iterable() 更适合这个操作,因为它一开始就假设你传入的是一个包含可迭代对象的单一可迭代对象。这样你的代码就可以简化为:

uniqueCrossTabs = list(itertools.chain.from_iterable(uniqueCrossTabs))

撰写回答