函数调用中的星号

问题:函数调用中的星号

我正在使用itertools.chain以这种方式“拉平”列表列表:

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

这跟说的有什么不同?

uniqueCrossTabs = list(itertools.chain(uniqueCrossTabs))

I’m using itertools.chain to “flatten” a list of lists in this fashion:

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

how is this different than saying:

uniqueCrossTabs = list(itertools.chain(uniqueCrossTabs))

回答 0

* 是“ splat”运算符:它接受一个列表作为输入,并将其扩展为函数调用中的实际位置参数。

所以如果uniqueCrossTabs[ [ 1, 2 ], [ 3, 4 ] ],那就itertools.chain(*uniqueCrossTabs)等于说itertools.chain([ 1, 2 ], [ 3, 4 ])

这与传递just显然不同uniqueCrossTabs。对于您的情况,您有一个想要拼合的列表列表;什么itertools.chain()确实是在所有你传递给它的位置参数,其中每个位置参数是在自己的权利迭代拼接返回一个迭代。

换句话说,您希望将每个列表uniqueCrossTabs作为参数传递给chain(),这会将它们链接在一起,但是您没有在单独的变量中使用列表,因此可以使用*运算符将列表扩展为多个列表参数。

正如Jochen Ritzel在评论中指出的那样,chain.from_iterable()它更适合于此操作,因为它假定一个可迭代的对象开始。然后,您的代码将变得简单:

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

* is the “splat” operator: It takes a list as input, and expands it into actual positional arguments in the function call.

So if uniqueCrossTabs was [ [ 1, 2 ], [ 3, 4 ] ], then itertools.chain(*uniqueCrossTabs) is the same as saying itertools.chain([ 1, 2 ], [ 3, 4 ])

This is obviously different from passing in just uniqueCrossTabs. In your case, you have a list of lists that you wish to flatten; what itertools.chain() does is return an iterator over the concatenation of all the positional arguments you pass to it, where each positional argument is iterable in its own right.

In other words, you want to pass each list in uniqueCrossTabs as an argument to chain(), which will chain them together, but you don’t have the lists in separate variables, so you use the * operator to expand the list of lists into several list arguments.

As Jochen Ritzel has pointed out in the comments, chain.from_iterable() is better-suited for this operation, as it assumes a single iterable of iterables to begin with. Your code then becomes simply:

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

回答 1

它将序列拆分为函数调用的单独参数。

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

It splits the sequence into separate arguments for the function call.

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

回答 2

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

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]

Just an alternative way of explaining the concept/using it.

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]