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

Why is it valid to assign to an empty list but not to an empty tuple?

这出现在 a recent PyCon talk

声明

[] = []

没有任何意义,但也不会抛出异常。我觉得这一定是由于拆包规则。您也可以对列表执行 tuple unpacking,例如

[a, b] = [1, 2]

如您所愿。作为合乎逻辑的结果,当要解包的元素数为 0 时,这也应该有效,这可以解释为什么分配给空列表是有效的。当您尝试将非空列表分配给空列表时发生的情况进一步支持了该理论:

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

如果元组也是如此,我会很高兴这个解释。如果我们可以解包成一个包含 0 个元素的列表,我们也应该可以解包成一个包含 0 个元素的元组,不是吗?然而:

>>> () = ()
  File "<stdin>", line 1
SyntaxError: can't assign to ()

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

当我被一些奇怪的东西绊倒时,我决定尝试使用 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 ()

不知何故 Python 编译器 特例了 LHS 上的一个空元组。此差异不同于 the specification,它指出:

Assignment of an object to a single target is recursively defined as follows.

...

  • If the target is a target list enclosed in parentheses or in square brackets: The object must be an iterable with the same number of items as there are targets in the target list, and its items are assigned, from left to right, to the corresponding targets.

看来您在 CPython(已测试 2.7.8 和 3.4.1)中发现了一个合法但最终无关紧要的错误。

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

@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);
}

tuples 明确检查长度是否为零并在为零时引发错误。 lists 没有任何此类检查,因此不会引发异常。

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

这是一个错误。

http://bugs.python.org/issue23275

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

“分配给列表”是错误的思考方式。

在所有情况下你都在解包:Python 解释器从所有三种写法中创建一个解包指令,不涉及列表或元组左侧(代码由 /u/old-man-prismo 提供):

>>> def f():
...     iterable = [1, 2]
...     a, b = iterable
...     (c, d) = iterable
...     [e, f] = iterable
...
>>> from dis import dis
>>> dis(f)
  2           0 LOAD_CONST               1 (1)
              3 LOAD_CONST               2 (2)
              6 BUILD_LIST               2
              9 STORE_FAST               0 (iterable)

  3          12 LOAD_FAST                0 (iterable)
             15 UNPACK_SEQUENCE          2
             18 STORE_FAST               1 (a)
             21 STORE_FAST               2 (b)

  4          24 LOAD_FAST                0 (iterable)
             27 UNPACK_SEQUENCE          2
             30 STORE_FAST               3 (c)
             33 STORE_FAST               4 (d)

  5          36 LOAD_FAST                0 (iterable)
             39 UNPACK_SEQUENCE          2
             42 STORE_FAST               5 (e)
             45 STORE_FAST               6 (f)
             48 LOAD_CONST               0 (None)
             51 RETURN_VALUE      

如您所见,三个语句完全相同。

现在拆包基本上是:

_iterator = iter(some_iterable)
a = next(_iterator)
b = next(_iterator)
for superfluous_element in _iterator:
    # this only happens if there’s something left
    raise SyntaxError('Expected some_iterable to have 2 elements')

类似地左侧有更多或更少的名字。

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

允许分配给 0 个名称才符合逻辑:为什么不呢?您基本上只是断言右侧的可迭代对象为空。该观点似乎也在 bug report @gecko 提到的共识中出现:让我们允许 () = iterable.