解包:[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
生成要分配给 a
和 b
的值。
即使你想争论字节码是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.
传达了更多信息
在 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
生成要分配给 a
和 b
的值。
即使你想争论字节码是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.