What is the difference in Python between unpacking a function call with []
, with ()
or with nothing?
def f():
return 0, 1
a, b = f() # 1
[a, b] = f() # 2
(a, b) = f() # 3
There is no difference. Regardless of what kind of syntactic sequence you use, the same byte code is generated.
>>> 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
In every case, you simply call f
, then use UNPACK_SEQUENCE
to produce the values to assign to a
and b
.
Even if you want to argue that byte code is an implementation detail of CPython, the definition of a chained assignment is not. Given
x = [a, b] = f()
the meaning is the same as
tmp = f()
x = tmp
[a, b] = tmp
x
is assigned the result of f()
(a tuple), not the "list" [a, b]
.
Finally, here is the grammar for an assignment statement:
assignment_stmt ::= (target_list "=")+ (starred_expression | yield_expression)
target_list ::= target ("," target)* [","]
target ::= identifier
| "(" [target_list] ")"
| "[" [target_list] "]"
| attributeref
| subscription
| slicing
| "*" target
Arguably, the "[" [target_list] "]"
could and should have been removed in Python 3. Such a breaking change would be difficult to implement now, given the stated preference to avoid any future changes to Python on the scale of the 2-to-3 transition.
As the other answer has explained, there is no semantic difference. The only reason to prefer one form over another is visual clarity; x, y = f()
is usually neater, but something like [(id,)] = do_sql_query()
may sometimes be written to indicate that the result is expected to be a list containing a tuple. The assignment target [(id,)]
is semantically equivalent to (id,),
but it communicates something more to the human reader.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With