Python语言(特别是3.x版本)允许对可迭代对象进行非常通用的解包操作,其中一个简单的例子是:
多年来,这种解包已逐渐被概括(例如参见PEP 3132和PEP 448),使其可以在更多情况下使用。因此,我惊讶地发现以下内容在Python 3.6中是无效的语法(在Python 3.7中仍然如此):
我可以通过将返回的元组放在括号中来使其正常工作,如下所示:
a, *rest = 1, 2, 3
多年来,这种解包已逐渐被概括(例如参见PEP 3132和PEP 448),使其可以在更多情况下使用。因此,我惊讶地发现以下内容在Python 3.6中是无效的语法(在Python 3.7中仍然如此):
def f():
rest = [2, 3]
return 1, *rest # Invalid
我可以通过将返回的元组放在括号中来使其正常工作,如下所示:
def f():
rest = [2, 3]
return (1, *rest) # Valid
我在return
语句中使用这个似乎很重要,因为
t = 1, *rest
这确实是合法的,并且带括号和不带括号的结果相同。
Python开发人员是否忘记了这个案例,还是有任何原因导致此案例成为无效语法?
为什么我关心这个问题
这违反了我认为我与Python语言之间的重要契约。考虑以下(也有效的)解决方案:
def f():
rest = [2, 3]
t = 1, *rest
return t
通常当我有像这样的代码时,我认为t
是一个临时名称,我应该能够通过在底部一行中用其定义替换t
来消除它。但在这种情况下,这会导致无效的代码。
def f():
rest = [2, 3]
return 1, *rest
当然,将返回值放在括号中并不是什么大问题,但通常只需要额外的括号来区分几个可能的结果(分组)。在这里,这不是问题,因为省略括号不会产生其他不想要的行为,而是根本没有行为。
更新
自Python 3.8以来(请参见此列表上的第7项),上述广义语法现在是有效的。
t = *rest
是无效的事实一致。此外,return *rest
和t = *rest
并不表示任何实际的解包操作,因此我认为不允许这样做并不是一个问题。如果允许这样做,则仅用*rest
将只是tuple(rest)
的混淆语法。 - jmd_dkreturn
。在yield
参数、下标、增量 赋值(但不是普通赋值)的 RHS 以及for
语句中的in
右侧,解包也是被禁止的。尽管在所有这些位置都允许使用未括号化元组,因为这些东西的语法使用的是expression_list
而不是starred_expression
。 - user2357112t = *rest
和t = *rest,
之间的差异,后者是有效的。 - senderlereturn *x
? - Dan Boschen