[Tutor] comma in an assignment
eryksun
eryksun at gmail.com
Wed Oct 23 03:35:06 CEST 2013
On Tue, Oct 22, 2013 at 3:20 PM, Key, Gregory E (E S SF RNA FSF 1 C)
<gregory.key at siemens.com> wrote:
> I understand that a comma in Python is a separator and not an operator. In
The comma operator creates a tuple. It has low precedence, so you
usually need parentheses. But sometimes the parentheses are redundant
such as with a return statement like `return (x, y, z)` vs `return x,
y, z`, or on the right-hand side of an assignment:
>>> y = 1, 2, 3
>>> y
(1, 2, 3)
> some of the MatPlotLib examples I see code like this:
>
> line1, = ax1.plot(t, y1, lw=2, color='red', label='1 HZ')
>
> What does the comma do in an assignment statement?
For an assignment target list, CPython doesn't actually create a
tuple. It's a notational tuple used by the compiler. It's present in
the abstract syntax tree (creating an AST is an intermediate step in
the compilation process); however, the final bytecode does sequence
unpacking directly to the target names. Here's the AST for `y, = x`:
>>> print ast.dump(ast.parse('y, = x').body[0])
Assign(targets=[Tuple(elts=[Name(id='y', ctx=Store())], ctx=Store())],
value=Name(id='x', ctx=Load()))
The AST Tuple in the assignment consists of one item, a Name with a
Store context. In this case, the compiler generates bytecode to unpack
a length 1 sequence and store the item to the name "y".
In practice this is pretty simple and intuitive:
>>> y, = [1]
>>> y
1
>>> x, y, z = 1, 2, 3
>>> x, y, z
(1, 2, 3)
You can use compile() and dis to see the bytecode itself:
>>> dis.dis(compile('y, = x', '', 'exec'))
1 0 LOAD_NAME 0 (x)
3 UNPACK_SEQUENCE 1
6 STORE_NAME 1 (y)
9 LOAD_CONST 0 (None)
12 RETURN_VALUE
The argument in UNPACK_SEQUENCE(1) is the number of items to unpack to
the frame's stack. For stack-based operations, think of using an RPN
calculator. An operator -- in this case a bytecode instruction -- pops
its operands off the stack and then pushes the result back on in their
place. The more complex the expression, the bigger the stack needs to
grow (think of a stack of plates) in order to hold temporary results.
Unpacking can also handle more complex structures such as `t, (x, y) = z`:
>>> z = [1, [2, 3]]
>>> t, (x, y) = z
>>> t, x, y
(1, 2, 3)
If you prefer, you can use square brackets on the left-hand side. The
compiled bytecode is the same, whether the left-hand side has Tuple or
List types in the AST:
>>> [t, [x, y]] = z
>>> t, x, y
(1, 2, 3)
Bytecode comparison:
>>> dis.dis(compile('t, (x, y) = z', '', 'exec'))
1 0 LOAD_NAME 0 (z)
3 UNPACK_SEQUENCE 2
6 STORE_NAME 1 (t)
9 UNPACK_SEQUENCE 2
12 STORE_NAME 2 (x)
15 STORE_NAME 3 (y)
18 LOAD_CONST 0 (None)
21 RETURN_VALUE
>>> dis.dis(compile('[t, [x, y]] = z', '', 'exec'))
1 0 LOAD_NAME 0 (z)
3 UNPACK_SEQUENCE 2
6 STORE_NAME 1 (t)
9 UNPACK_SEQUENCE 2
12 STORE_NAME 2 (x)
15 STORE_NAME 3 (y)
18 LOAD_CONST 0 (None)
21 RETURN_VALUE
After the first unpack, item 0 is popped off the stack and stored to
t. Next item 1 (a length 2 sequence) is popped, unpacked, and stored
to x and y.
More information about the Tutor
mailing list