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

j0k*_*ker 30 python iterable-unpacking

这是在最近的PyCon演讲中提出的.

该声明

[] = []
Run Code Online (Sandbox Code Playgroud)

没有任何意义,但它也没有抛出异常.我觉得这一定是因为拆包规则.您也可以使用列表进行元组拆包,例如,

[a, b] = [1, 2]
Run Code Online (Sandbox Code Playgroud)

做你所期望的.作为逻辑结果,当解包的元素数为0时,这也应该有效,这可以解释为什么分配给空列表是有效的.当您尝试将非空列表分配给空列表时会发生什么,这进一步支持了这一理论:

>>> [] = [1]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: too many values to unpack
Run Code Online (Sandbox Code Playgroud)

如果对于元组也是如此,我会对这个解释感到满意.如果我们可以解压缩到包含0个元素的列表,我们也应该能够解包为具有0个元素的元组,不是吗?然而:

>>> () = ()
  File "<stdin>", line 1
SyntaxError: can't assign to ()
Run Code Online (Sandbox Code Playgroud)

似乎解包规则不适用于元组,因为它们用于列表.我想不出对这种不一致的任何解释.这种行为有原因吗?

Blc*_*ght 20

@ user2357112的评论似乎是巧合似乎是正确的.Python源代码的相关部分是Python/ast.c:

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);
}
Run Code Online (Sandbox Code Playgroud)

tuples有一个明确的检查,长度不是零,并在它出现时引发错误.list没有任何这样的检查,所以没有例外.

当分配给空元组是一个错误时,我没有看到允许赋值给空列表的任何特殊原因,但也许有一些我不考虑的特殊情况.我建议这可能是一个(微不足道的)错误,并且这两种类型的行为应该是相同的.

  • @clj:不在作业的左侧,它不是. (6认同)

Ign*_*ams 12

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 ()
Run Code Online (Sandbox Code Playgroud)

不知何故,Python 编译器特殊情况下LHS上的空元组.这种差异因规格而异,其中规定:

如下递归地定义对象到单个目标的分配.

...

  • 如果目标是括在括号中或方括号中的目标列表:对象必须是与目标列表中的目标具有相同数量的项目的可迭代对象,并且其项目从左到右分配给相应的目标.

所以看起来你已经在CPython中找到了一个合法的,虽然最终无关紧要的错误(2.7.8和3.4.1测试).

IronPython 2.6.1表现出相同的区别,但是Jython 2.7b3 +有一个陌生人的行为,() = ()开始一个看似无法结束它的声明.

  • [根据规范](https://docs.python.org/3/reference/simple_stmts.html#assignment-statements),它应该拒绝`[] = []`和`()= []`. (2认同)