解包:[x,y], (x,y), x,y - 有什么区别?

Unpacking: [x,y], (x,y), x,y - what is the difference?

在 Python 中,使用 []、使用 () 或什么都不打开函数调用有什么区别?

def f():
    return 0, 1

a, b = f() # 1
[a, b] = f() # 2
(a, b) = f() # 3

没有区别。无论您使用哪种 syntactic 序列,都会生成相同的字节码。

>>> def f():
...   return 0, 1
...
>>> import dis
>>> dis.dis('[a,b] = f()')
  1           0 LOAD_NAME                0 (f)
              2 CALL_FUNCTION            0
              4 UNPACK_SEQUENCE          2
              6 STORE_NAME               1 (a)
              8 STORE_NAME               2 (b)
             10 LOAD_CONST               0 (None)
             12 RETURN_VALUE
>>> dis.dis('(a,b) = f()')
  1           0 LOAD_NAME                0 (f)
              2 CALL_FUNCTION            0
              4 UNPACK_SEQUENCE          2
              6 STORE_NAME               1 (a)
              8 STORE_NAME               2 (b)
             10 LOAD_CONST               0 (None)
             12 RETURN_VALUE
>>> dis.dis('a, b = f()')
  1           0 LOAD_NAME                0 (f)
              2 CALL_FUNCTION            0
              4 UNPACK_SEQUENCE          2
              6 STORE_NAME               1 (a)
              8 STORE_NAME               2 (b)
             10 LOAD_CONST               0 (None)
             12 RETURN_VALUE

在任何情况下,您只需调用 f,然后使用 UNPACK_SEQUENCE 生成要分配给 ab 的值。


即使你想争论字节码是CPython的实现细节,链式赋值的定义也是不是。鉴于

x = [a, b] = f()

意思同

tmp = f()
x = tmp
[a, b] = tmp

x 被赋值为 f()(元组)的结果,而不是“列表”[a, b].


最后,这是赋值语句的语法:

assignment_stmt ::=  (target_list "=")+ (starred_expression | yield_expression)
target_list     ::=  target ("," target)* [","]
target          ::=  identifier
                     | "(" [target_list] ")"
                     | "[" [target_list] "]"
                     | attributeref
                     | subscription
                     | slicing
                     | "*" target

可以说,"[" [target_list] "]" 可以而且应该在 Python 3 中删除。考虑到声明的偏好,即避免将来对 [= 进行任何更改,这样的重大更改现在很难实施42=] 在 2 到 3 过渡的规模上。

正如其他答案所解释的,没有语义差异。喜欢一种形式而不是另一种形式的唯一原因是视觉清晰度; x, y = f() 通常更简洁,但有时可能会写成 [(id,)] = do_sql_query() 之类的东西,以表明预期结果是包含元组的列表。赋值目标 [(id,)] 在语义上等同于 (id,), 但它与人类 reader.

传达了更多信息