171

I tried to use multiple assignment as show below to initialize variables, but I got confused by the behavior, I expect to reassign the values list separately, I mean b[0] and c[0] equal 0 as before.

a=b=c=[0,3,5]
a[0]=1
print(a)
print(b)
print(c)

Result is: [1, 3, 5] [1, 3, 5] [1, 3, 5]

Is that correct? what should I use for multiple assignment? what is different from this?

d=e=f=3
e=4
print('f:',f)
print('e:',e)

result: ('f:', 3) ('e:', 4)

Marco
  • 4,000
  • 3
  • 25
  • 26
  • 3
    Do you want `a`, `b`, and `c,` to all point to the same value (in this case a list), or do you want `a=0`, `b=3`, and `c=5`. In that case, you want `a,b,c = [0,3,5]` or just `a,b,c = 0,3,5`. – chepner May 02 '13 at 22:52

14 Answers14

323

If you're coming to Python from a language in the C/Java/etc. family, it may help you to stop thinking about a as a "variable", and start thinking of it as a "name".

a, b, and c aren't different variables with equal values; they're different names for the same identical value. Variables have types, identities, addresses, and all kinds of stuff like that.

Names don't have any of that. Values do, of course, and you can have lots of names for the same value.

If you give Notorious B.I.G. a hot dog,* Biggie Smalls and Chris Wallace have a hot dog. If you change the first element of a to 1, the first elements of b and c are 1.

If you want to know if two names are naming the same object, use the is operator:

>>> a=b=c=[0,3,5]
>>> a is b
True

You then ask:

what is different from this?

d=e=f=3
e=4
print('f:',f)
print('e:',e)

Here, you're rebinding the name e to the value 4. That doesn't affect the names d and f in any way.

In your previous version, you were assigning to a[0], not to a. So, from the point of view of a[0], you're rebinding a[0], but from the point of view of a, you're changing it in-place.

You can use the id function, which gives you some unique number representing the identity of an object, to see exactly which object is which even when is can't help:

>>> a=b=c=[0,3,5]
>>> id(a)
4473392520
>>> id(b)
4473392520
>>> id(a[0])
4297261120
>>> id(b[0])
4297261120

>>> a[0] = 1
>>> id(a)
4473392520
>>> id(b)
4473392520
>>> id(a[0])
4297261216
>>> id(b[0])
4297261216

Notice that a[0] has changed from 4297261120 to 4297261216—it's now a name for a different value. And b[0] is also now a name for that same new value. That's because a and b are still naming the same object.


Under the covers, a[0]=1 is actually calling a method on the list object. (It's equivalent to a.__setitem__(0, 1).) So, it's not really rebinding anything at all. It's like calling my_object.set_something(1). Sure, likely the object is rebinding an instance attribute in order to implement this method, but that's not what's important; what's important is that you're not assigning anything, you're just mutating the object. And it's the same with a[0]=1.


user570826 asked:

What if we have, a = b = c = 10

That's exactly the same situation as a = b = c = [1, 2, 3]: you have three names for the same value.

But in this case, the value is an int, and ints are immutable. In either case, you can rebind a to a different value (e.g., a = "Now I'm a string!"), but the won't affect the original value, which b and c will still be names for. The difference is that with a list, you can change the value [1, 2, 3] into [1, 2, 3, 4] by doing, e.g., a.append(4); since that's actually changing the value that b and c are names for, b will now b [1, 2, 3, 4]. There's no way to change the value 10 into anything else. 10 is 10 forever, just like Claudia the vampire is 5 forever (at least until she's replaced by Kirsten Dunst).


* Warning: Do not give Notorious B.I.G. a hot dog. Gangsta rap zombies should never be fed after midnight.

abarnert
  • 354,177
  • 51
  • 601
  • 671
  • What if we `have, a = b = c = 10;` and when we try to update the value of b, it does effect any other? although i checked their ids are the same.? – A.J. Aug 11 '14 at 14:42
  • 2
    @user570826: `10` is immutable—that means there is no way to update the value, so your question doesn't make sense. You can point `b` at a different value, but doing so has no effect on `a` and `c`, which are still pointing at the original value. The difference that lists make is that they're mutable—e.g., you can `append` to a list, or `lst[0] = 3`, and that will update the value, which will be visible through all names for that value. – abarnert Aug 11 '14 at 17:43
  • "If you give Notorious B.I.G. a hot dog,* Biggie Smalls and Chris Wallace have a hot dog." I don't know who these people are, could you use a different example, maybe something not so culture based? – Bassie-c Mar 05 '22 at 21:50
  • 1
    @Bassie-c, this answer is from 2013. Most people coding at that time would have been old enough to know Notorious B.I.G. People to young to know Notorious B.I.G, are young enough to know Google. This means you must have born before the 70's or so. So let's try this: If you give the `King of Rock and Roll` a hot dog*, `Elvis-the-Pelvis` and `E. A. Presley` have a hot dog. *_Don't worry, the King is still alive! So no need to worry if he is a zombie if you see him, and you can feed him all you want._ – Lu Kas Sep 15 '22 at 15:05
102

Cough cough

>>> a,b,c = (1,2,3)
>>> a
1
>>> b
2
>>> c
3
>>> a,b,c = ({'test':'a'},{'test':'b'},{'test':'c'})
>>> a
{'test': 'a'}
>>> b
{'test': 'b'}
>>> c
{'test': 'c'}
>>> 
Jimmy Kane
  • 16,223
  • 11
  • 86
  • 117
  • 18
    IMHO, this actually answers OP first key question of what should I use for multiple assignment, whereas the higher rated and more cerebral answer above doesn't. – Will Croxford Feb 13 '19 at 11:08
  • 8
    Or `a,b,c = 1,2,3` without brackets works in Python 2 or 3, if u really want that extra cm of readibility. – Will Croxford Sep 18 '19 at 13:39
18

In python, everything is an object, also "simple" variables types (int, float, etc..).

When you changes a variable value, you actually changes it's pointer, and if you compares between two variables it's compares their pointers. (To be clear, pointer is the address in physical computer memory where a variable is stored).

As a result, when you changes an inner variable value, you changes it's value in the memory and it's affects all the variables that point to this address.

For your example, when you do:

a = b =  5 

This means that a and b points to the same address in memory that contains the value 5, but when you do:

a = 6

It's not affect b because a is now points to another memory location that contains 6 and b still points to the memory address that contains 5.

But, when you do:

a = b = [1,2,3]

a and b, again, points to the same location but the difference is that if you change the one of the list values:

a[0] = 2

It's changes the value of the memory that a is points on, but a is still points to the same address as b, and as a result, b changes as well.

Ori Seri
  • 917
  • 1
  • 6
  • 14
  • 6
    This is highly misleading. Pointers are certainly not visible at the Python level, and at least two of the four major implementations (PyPy and Jython) don't use them even inside the implementation. – abarnert May 02 '13 at 23:15
  • 1
    You welcome to read and explore python internals and you'll discover that every variable in python is actually pointer. – Ori Seri May 02 '13 at 23:21
  • 4
    No. In _one implementation_ of Python (CPython), every variable is a pointer to a `PyObject`. That's not true in other implementations like PyPy or Jython. (In fact, it's not even clear how it _could_ be true, because the languages those implementations are written in don't even have pointers.) – abarnert May 02 '13 at 23:29
  • I think the use of "pointer" in a conceptual sense is ok (perhaps with a disclaimer that implementations may vary), esp if the goal is to convey behavior. – Levon Aug 05 '15 at 14:47
  • @abarnert When people say Python they mean CPython, not other rarely used implementations. Just like when people say Kleenex they mean facial tissue. Playing the semantics game in these comments is really unnecessary. As for what he wrote, is the behavior of what he described wrong? – swade Jul 17 '18 at 18:44
  • @StevenWade Besides the fact that you're replying to a 5-year-old comment: Python is defined in an implementation-agnostic way not just to allow things like PyPy and MicroPython (which are not that rarely used, especially not compared to 2013) to exist, but also to make the language clearer. But that's not even the reason the answer is misleading; just replying to the last in a chain of comments (with all of the intermediate comments long deleted) is kind of missing the point. – abarnert Jul 17 '18 at 18:54
15

Yes, that's the expected behavior. a, b and c are all set as labels for the same list. If you want three different lists, you need to assign them individually. You can either repeat the explicit list, or use one of the numerous ways to copy a list:

b = a[:] # this does a shallow copy, which is good enough for this case
import copy
c = copy.deepcopy(a) # this does a deep copy, which matters if the list contains mutable objects

Assignment statements in Python do not copy objects - they bind the name to an object, and an object can have as many labels as you set. In your first edit, changing a[0], you're updating one element of the single list that a, b, and c all refer to. In your second, changing e, you're switching e to be a label for a different object (4 instead of 3).

HoldOffHunger
  • 18,769
  • 10
  • 104
  • 133
Peter DeGlopper
  • 36,326
  • 7
  • 90
  • 83
13

You can use id(name) to check if two names represent the same object:

>>> a = b = c = [0, 3, 5]
>>> print(id(a), id(b), id(c))
46268488 46268488 46268488

Lists are mutable; it means you can change the value in place without creating a new object. However, it depends on how you change the value:

>>> a[0] = 1
>>> print(id(a), id(b), id(c))
46268488 46268488 46268488
>>> print(a, b, c)
[1, 3, 5] [1, 3, 5] [1, 3, 5]

If you assign a new list to a, then its id will change, so it won't affect b and c's values:

>>> a = [1, 8, 5]
>>> print(id(a), id(b), id(c))
139423880 46268488 46268488
>>> print(a, b, c)
[1, 8, 5] [1, 3, 5] [1, 3, 5]

Integers are immutable, so you cannot change the value without creating a new object:

>>> x = y = z = 1
>>> print(id(x), id(y), id(z))
507081216 507081216 507081216
>>> x = 2
>>> print(id(x), id(y), id(z))
507081248 507081216 507081216
>>> print(x, y, z)
2 1 1
tyteen4a03
  • 1,812
  • 24
  • 45
jurgenreza
  • 5,856
  • 2
  • 25
  • 37
  • 1
    `id` isn't necessarily a memory location. As [the docs](http://docs.python.org/2/library/functions.html#id) say, this returns the "identity… an integer… which is guaranteed to be unique and constant for this object during its lifetime." CPython happens to use the memory address as the `id`, but other Python implementations may not. PyPy, for example, doesn't. And saying "two vars point to the same memory location" is misleading to anyone who understands it C-style. "Two names for the same object" is both more accurate and less misleading. – abarnert May 02 '13 at 23:18
7

in your first example a = b = c = [1, 2, 3] you are really saying:

 'a' is the same as 'b', is the same as 'c' and they are all [1, 2, 3]

If you want to set 'a' equal to 1, 'b' equal to '2' and 'c' equal to 3, try this:

a, b, c = [1, 2, 3]

print(a)
--> 1
print(b)
--> 2
print(c)
--> 3

Hope this helps!

Nick Burns
  • 973
  • 6
  • 4
4

What you need is this:

a, b, c = [0,3,5] # Unpack the list, now a, b, and c are ints
a = 1             # `a` did equal 0, not [0,3,5]
print(a)
print(b)
print(c)
pydsigner
  • 2,779
  • 1
  • 20
  • 33
4

Simply put, in the first case, you are assigning multiple names to a list. Only one copy of list is created in memory and all names refer to that location. So changing the list using any of the names will actually modify the list in memory.

In the second case, multiple copies of same value are created in memory. So each copy is independent of one another.

Vikas
  • 1,900
  • 1
  • 19
  • 20
3

The code that does what I need could be this:

# test

aux=[[0 for n in range(3)] for i in range(4)]
print('aux:',aux)

# initialization

a,b,c,d=[[0 for n in range(3)] for i in range(4)]

# changing values

a[0]=1
d[2]=5
print('a:',a)
print('b:',b)
print('c:',c)
print('d:',d)

Result:

('aux:', [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]])
('a:', [1, 0, 0])
('b:', [0, 0, 0])
('c:', [0, 0, 0])
('d:', [0, 0, 5])
Nathan Arthur
  • 8,287
  • 7
  • 55
  • 80
Marco
  • 4,000
  • 3
  • 25
  • 26
1

To assign multiple variables same value I prefer list

a, b, c = [10]*3#multiplying 3 because we have 3 variables
print(a, type(a), b, type(b), c, type(c))

output:

10 <class 'int'> 10 <class 'int'> 10 <class 'int'>

Initialize multiple objects:

import datetime

time1, time2, time3 = [datetime.datetime.now()]*3

print(time1)
print(time2)
print(time3)

output:

2022-02-25 11:52:59.064487
2022-02-25 11:52:59.064487
2022-02-25 11:52:59.064487
Udesh
  • 2,415
  • 2
  • 22
  • 32
1

E.g: basically a = b = 10 means both a and b are pointing to 10 in the memory, you can test by id(a) and id(b) which comes out exactly equal to a is b as True.

is matches the memory location but not its value, however == matches the value.

let's suppose, you want to update the value of a from 10 to 5, since the memory location was pointing to the same memory location you will experience the value of b will also be pointing to 5 because of the initial declaration.

The conclusion is to use this only if you know the consequences otherwise simply use , separated assignment like a, b = 10, 10 and won't face the above-explained consequences on updating any of the values because of different memory locations.

0

The behavior is correct. However, all the variables will share the same reference. Please note the behavior below:

>>> a = b = c = [0,1,2]
>>> a
[0, 1, 2]
>>> b
[0, 1, 2]
>>> c 
[0, 1, 2]
>>> a[0]=1000
>>> a
[1000, 1, 2]
>>> b
[1000, 1, 2]
>>> c
[1000, 1, 2]

So, yes, it is different in the sense that if you assign a, b and c differently on a separate line, changing one will not change the others.

Yigit Alparslan
  • 1,377
  • 1
  • 8
  • 13
0

Here are two codes for you to choose one:

a = b = c = [0, 3, 5]
a = [1, 3, 5]
print(a)
print(b)
print(c)

or

a = b = c = [0, 3, 5]
a = [1] + a[1:]
print(a)
print(b)
print(c)
My Car
  • 4,198
  • 5
  • 17
  • 50
0

The reason for observed behavior was already described in other comments, but there was no solution given, which could help to achieve the required result in a "similar way" as it was given in the topic-description.
I would give a try:

import copy

s = [0,3,5] # Define a value we would like to assign
a,b,c=(copy.deepcopy(s) for _ in range(3)) # assign same value to variables a,b,c as its "deep copy"

# Same as a single line:
a,b,c=(copy.deepcopy([0,3,5]) for _ in range(3))

In my example - changing of a would neither affect b nor c .

Dr.CKYHC
  • 11
  • 2