Python 为什么分配给空列表而不是空元组是有效的?

Python 为什么分配给空列表而不是空元组是有效的?,python,iterable-unpacking,Python,Iterable Unpacking,这件事是在一年前发生的 声明 [] = [] 没有任何有意义的操作,但也不会引发异常。我觉得这一定是因为拆包规则。您也可以使用列表,例如 [a, b] = [1, 2] 做你想做的事。从逻辑上讲,当要解包的元素数为0时,这也应该起作用,这可以解释为什么分配给空列表是有效的。当您尝试将一个非空列表分配给一个空列表时,会发生什么情况,这进一步支持了该理论: >>> [] = [1] Traceback (most recent call last): File "<s

这件事是在一年前发生的

声明

[] = []
没有任何有意义的操作,但也不会引发异常。我觉得这一定是因为拆包规则。您也可以使用列表,例如

[a, b] = [1, 2]
做你想做的事。从逻辑上讲,当要解包的元素数为0时,这也应该起作用,这可以解释为什么分配给空列表是有效的。当您尝试将一个非空列表分配给一个空列表时,会发生什么情况,这进一步支持了该理论:

>>> [] = [1]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: too many values to unpack
>>[]=[1]
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
ValueError:要解压缩的值太多
如果元组也是这样的话,我很乐意接受这个解释。如果我们可以解包到一个包含0个元素的列表,那么我们也应该能够解包到一个包含0个元素的元组,不是吗?然而:

>>> () = ()
  File "<stdin>", line 1
SyntaxError: can't assign to ()
>>>()=()
文件“”,第1行
SyntaxError:无法分配给()

解包规则似乎不像用于列表那样适用于元组。我想不出任何解释来解释这种不一致。这种行为有什么原因吗

当我被一些奇怪的事情绊倒时,我决定尝试使用
dis
来了解这里发生了什么:

>>> def foo():
...   [] = []
... 
>>> dis.dis(foo)
  2           0 BUILD_LIST               0
              3 UNPACK_SEQUENCE          0
              6 LOAD_CONST               0 (None)
              9 RETURN_VALUE        
>>> def bar():
...   () = ()
... 
  File "<stdin>", line 2
SyntaxError: can't assign to ()
>>def foo():
...   [] = []
... 
>>>dis.dis(foo)
2 0生成列表0
3解包\u序列0
6负载常数0(无)
9返回值
>>>def bar():
...   () = ()
... 
文件“”,第2行
SyntaxError:无法分配给()
不知何故,Python编译器在LHS上使用了一个空元组。这种差异因以下情况而有所不同:

将对象分配给单个目标的递归定义如下

  • 如果目标是用括号或方括号括起来的目标列表:对象必须是一个iterable,其项数必须与目标列表中的目标数相同,并且其项数从左到右分配给相应的目标
因此,看起来您在CPython(2.7.8和3.4.1测试版)中发现了一个合法但最终无关紧要的bug


IronPython 2.6.1表现出相同的差异,但Jython 2.7b3+有一个奇怪的行为,
()=()
开始一个语句时似乎没有办法结束它。

@user2357112关于这似乎是巧合的评论似乎是正确的。Python源代码的相关部分位于:

tuple
s会显式检查长度是否为零,并在长度为零时引发错误<代码>列表s没有任何此类检查,因此没有引发异常

当赋值给空元组是一个错误时,我不认为允许赋值给空列表有什么特别的原因,但也许有一些特殊情况我没有考虑。我认为这可能是一个(微不足道的)错误,两种类型的行为应该相同。

这是一个错误


但是,它似乎是无害的,因此我怀疑它是否会得到修复,因为我担心会破坏工作代码。

考虑它时,“分配给列表”是错误的

在所有情况下,您都在解包:Python解释器通过所有三种编写方式创建解包指令,左侧没有涉及列表或元组(代码由提供):

>>def():
...     iterable=[1,2]
...     a、 b=可测量
...     (c,d)=可计算
...     [e,f]=可数
...
>>>从dis导入dis
>>>dis(f)
2 0负载常数1(1)
3负载常数2(2)
6构建列表2
9存储快速0(可编辑)
3 12快速加载0(可调)
15按顺序2拆包
18商店快速1(a)
21商店2(b)
4 24负载快速0(可调)
27拆包顺序2
30商店3(c)
33商店快速4(d)
5 36加载速度0(可调)
39拆包顺序2
42商店快速5(e)
45商店6(f)
48负载常数0(无)
51返回值
如您所见,这三种说法完全相同

解包现在主要做的是:

\u iterator=iter(一些可计算)
a=下一个(_迭代器)
b=下一个(_迭代器)
对于_迭代器中多余的_元素:
#只有在有东西留下的情况下才会发生这种情况
raise SYNTEXERROR('预期某些\u iterable包含2个元素')
类似地,在左边有或多或少的名字

正如@blckknght所说的:编译器出于某种原因检查左侧是否为空元组,并且不允许这样做,但如果它是空列表,则不允许这样做


只允许为0分配名称是一致的和合乎逻辑的:为什么不?您基本上只是断言右边的iterable是空的。这种观点似乎在@gecko提到的@gecko中也形成了共识:让我们允许
()=iterable

@ozgur,但用元组解包确实有效:
a,b=1,2
是有效的……我不确定,但我认为
[]=[]
不是解包。然而,当我看到这是可行的时,我感到惊讶:
[a,b]=[1,2]
。相反,我会做
a,b=(1,2)
我感觉这里不会有任何有趣的原理在起作用。最好的答案可能是这样的:“这是代码生成器的一部分,它检查分配的LHS的有效性,这是一个检查,它捕获
()
,但让
[]
通过”。可能是因为
()
被识别为常量或其他东西。@ozgur
switch (e->kind) {
    # several cases snipped
    case List_kind:
        e->v.List.ctx = ctx;
        s = e->v.List.elts;
        break;
    case Tuple_kind:
        if (asdl_seq_LEN(e->v.Tuple.elts))  {
            e->v.Tuple.ctx = ctx;
            s = e->v.Tuple.elts;
        }
        else {
            expr_name = "()";
        }
        break;
    # several more cases snipped
}
/* Check for error string set by switch */
if (expr_name) {
    char buf[300];
    PyOS_snprintf(buf, sizeof(buf),
                  "can't %s %s",
                  ctx == Store ? "assign to" : "delete",
                  expr_name);
    return ast_error(c, n, buf);
}