Python: 在Python中,星号/解包运算符*不能用于表达式?

32

有没有人知道为什么在涉及迭代器/列表/元组的表达式中不能使用一元 (*) 运算符?

为什么它只限于函数展开?或者是我想错了吗?

例如:

>>> [1,2,3, *[4,5,6]]
File "<stdin>", line 1
[1,2,3, *[4,5,6]]
        ^
SyntaxError: invalid syntax

为什么 * 运算符不起作用:

[1, 2, 3, *[4, 5, 6]] give [1, 2, 3, 4, 5, 6]

而当*运算符与函数调用一起使用时,它会进行展开:

f(*[4, 5, 6]) is equivalent to f(4, 5, 6)

在使用列表时,+* 之间存在相似性,但在将列表扩展到另一种类型时则不然。

例如:

# This works
gen = (x for x in range(10))

def hello(*args):
    print args    
hello(*gen)

# but this does not work
[] + gen
TypeError: can only concatenate list (not "generator") to list

你对那个用法有什么期望?我的意思是,你为什么想要这样做? - Lafexlos
好的,我会更新我的问题。 - Har
看起来这是两个不同的问题:第一个与语法相关,第二个只是list.__add__的行为。 - Tamas Hegedus
3个回答

47

在Python 3.5中,通过PEP 448所述,可以在列表、字典、集合和元组字面量中进行解包:

Python 3.5.0 (v3.5.0:374f501f4567, Sep 13 2015, 02:27:37) on Windows (64 bits).

>>> [1, 2, 3, *[4, 5, 6]]
[1, 2, 3, 4, 5, 6]

这里有一些关于这个改变背后的原因的解释。请注意,这并不意味着在所有情况下*[1, 2, 3]等同于1, 2, 3。Python的语法并不是用来这样工作的。


请使用完整的信息,但我们讨论的是python-2.7(请参见问题中的标签)。 - Andriy Ivaneyko
似乎在制作Python 2.7时,他们没有考虑到在容器内使用*的情况? - Har
3
@AndriyIvaneyko这个回答回答了所提出的问题。楼主想知道推理过程,而不是如何在Py2.7中以另一种方式完成它。 - timgeb

5
星号*不仅是一元运算符,它还是用于函数定义函数调用参数解包的参数解包运算符

所以*只应该用于处理函数参数,而不是列表、元组等。

注意:从Python3.5开始,* 不仅可以与函数参数一起使用,@B.M 的答案详细描述了Python中的更改。

如果您需要连接列表,请使用连接操作而不是list1 + list2来获取所需结果。 要连接列表和generator,只需将generator传递给list类型对象,然后再与另一个列表连接即可:

gen = (x for x in range(10))
[] + list(gen)

1
它适用于函数调用和函数定义。你的表述似乎有点暗示它只适用于后一种情况,因此你可能需要编辑措辞。 - SuperBiasedMan
1
@SuperBiasedMan 谢谢,我已经更新了答案。 - Andriy Ivaneyko

3

该语法不被支持。虽然Python 2在赋值的左侧不支持*,但Python 3会提供更好的错误提示信息:

Python 3.4.3+ (default, Oct 14 2015, 16:03:50) 
>>> [1,2,3, *[4,5,6]]
  File "<stdin>", line 1
SyntaxError: can use starred expression only as assignment target
>>> 

f(*[4,5,6]) 等价于 f(4,5,6)

函数参数展开是一个特殊情况。


2
谢谢您指出Python 3,我刚试过了,它确实可以在Python 3.5.1中运行。我之前不知道这一点。它甚至可以与生成器一起使用 :) 非常酷![1,2,3,(x for x in range(10))] >>> [*[1,2,3,4]] => [1, 2, 3, 4] - Har

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接