I'm going through some old code trying to understand what it does, and I came across this odd statement:
*x ,= p
p
is a list in this context. I've been trying to figure out what this statement does. As far as I can tell, it just sets x
to the value of p
. For example:
p = [1,2]
*x ,= p
print(x)
Just gives
[1, 2]
So is this any different than x = p
? Any idea what this syntax is doing?
It's a feature that was introduced in Python 3.0 (PEP 3132). In Python 2, you could do something like this:
Python 3 extended this so that one variable could hold multiple values:
This, therefore, is what is being used here. Instead of two variables to hold three values, however, it is just one variable that takes each value in the list. This is different from
x = p
becausex = p
just means thatx
is another name forp
. In this case, however, it is a new list that just happens to have the same values in it. (You may be interested in "Least Astonishment" and the Mutable Default Argument)Two other common ways of producing this effect are:
and
Since Python 3.3, the list object actually has a method intended for copying:
The slice is actually a very similar concept. As nneonneo pointed out, however, that works only with objects such as lists and tuples that support slices. The method you mention, however, works with any iterable: dictionaries, sets, generators, etc.
*x ,= p
is basically an obfuscated version ofx = list(p)
using extended iterable unpacking. The comma afterx
is required to make the assignment target a tuple (it could also be a list though).*x, = p
is different fromx = p
because the former creates a copy ofp
(i.e. a new list) while the latter creates a reference to the original list. To illustrate:You should always throw these to
dis
and see what it throws back at you; you'll see how*x, = p
is actually different fromx = p
:While, the simple assignment statement:
(Stripping off unrelated
None
returns)As you can see
UNPACK_EX
is the different op-code between these; it's documented as:Which is why, as Eugene noted, you get a new object that's referred to by the name
x
and not a reference to an already existing object (as is the case withx = p
).*x,
does seem very odd (the extra comma there and all) but it is required here. The left hand side must either be a tuple or a list and, due to the quirkiness of creating a single element tuple in Python, you need to use a trailing,
:If you like confusing people, you can always use the
list
version of this:which does exactly the same thing but doesn't have that extra comma hanging around there.