【发布时间】:2018-04-26 14:45:54
【问题描述】:
Python 语言(尤其是 3.x)允许非常通用的解包迭代,一个简单的例子是
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 开始(参见 this list 的第 7 项),上面讨论的通用语法现在有效。
【问题讨论】:
-
这实际上是grammar syntax 的结果。
-
你也不能只返回 *rest,这是无效的语法。
-
@lapisdecor 是的,但这与
t = *rest无效的事实一致。另外,return *rest和t = *rest并不代表任何实际的拆包,所以我不认为这是不允许的问题。如果允许,*rest本身只会是tuple(rest)的令人困惑的语法。 -
这种情况不仅仅发生在
return上。在yield参数、下标、augmented 赋值(但不是常规赋值)的 RHS 以及for语句中的in右侧也禁止拆包,尽管所有这些位置都允许使用无括号的元组,因为这些东西的语法使用expression_list而不是starred_expression。 -
注意
t = *rest和t = *rest,之间的区别。后者是有效的。
标签: python python-3.x return tuples iterable-unpacking