69

When I try this code:

dict_a = dict_b = dict_c = {}
dict_c['hello'] = 'goodbye'

print(dict_a)
print(dict_b)
print(dict_c)

I expected that it would just initialise the dict_a, dict_b and dict_c dictionaries, and then assign a key in dict_c, resulting in

{}
{}
{'hello': 'goodbye'}

But it seems to have a copy-through effect instead:

{'hello': 'goodbye'}
{'hello': 'goodbye'}
{'hello': 'goodbye'}

Why?


See also:

3
  • No tutorial, I was just applying concepts I thought worked in languages such as Java. Commented Mar 15, 2010 at 15:55
  • 2
    "But it seams to have a copy through effect:" The behaviour here is exactly because it doesn't copy. Copying would mean that each variable got its own separate {} value. Instead, they get the same empty dictionary, and are just different names for it. Commented Aug 12, 2022 at 3:33
  • 2
    It didn't exist at the time this question was asked, but those finding this question now should read nedbatchelder.com/text/names.html. Commented Sep 2, 2022 at 20:34

5 Answers 5

61

This is because in Python, variables (names) are just references to individual objects. When you assign dict_a = dict_b, you are really copying a memory address (or pointer, if you will) from dict_b to dict_a. There is still one instance of that dictionary.

To get the desired behavior, use either the dict.copy method, or use copy.deepcopy if your dict may have nested dicts or other nested objects.

>>> a = {1:2}
>>> b = a.copy()
>>> b
{1: 2}
>>> b[3] = 4
>>> a
{1: 2}
>>> b
{1: 2, 3: 4}
>>> 
Sign up to request clarification or add additional context in comments.

7 Comments

So dictionaries are objects, would this still be the case with say an integer variable or would the type of a variable have no impact on it being an object?
Integers are immutable so I'm not sure how you would intend to reproduce this behavior. In any case, literal values for some types are interned (ie there is only one instance of each). You can verify that two integer variables containing the same value actually point to the same instance of the integer via the id() function.
In any case, everything in Python is an object. To see the functions that belong to the integer object 1, you can execute dir(1).
Everything is an object, and variables are names that we assign to objects (not the other way around!) So if you do a = b = c = 1; a +=1, then everything gets assigned to the object 1, and then a gets assigned to the object 2. With mutable objects like lists, dicts and sets, you can change the object itself, which will be seen by all names assigned to that object, but with ints, strings, tuples, and other immutable objects, all you can do is assign the name to a different object.
"objects are just references" This is not true. Objects are objects. Names reference them.
|
10

Even though

>>> dict_a, dict_b, dict_c = {}, {}, {}

is the right way to go in most cases, when it get more than 3 it looks weird

Imagine

>>> a, b, c, d, e, f = {}, {}, {}, {}, {}, {}

In cases where I wanna initialize more than 3 things, I use

>>> a, b, c, d, e, f, = [dict() for x in range(6)]

5 Comments

"Caution: Do not use [{} for x in range(6)]" Why not? the element expression gets executed once for each iteration, and each time a literal {} gets executed, it returns a new dict. In fact, this should be preferred over dict() since it avoids a function call.
@TokenMacGuy, yes and no. Now that I re-read what I wrote I see your point. {} gets initialized everytime time. That said {} is just a syntax sugar for dict(). You're not saving anything by using former.
Jeffrey Jose: Doubting Thomas aye? import dis; print dis.dis(lambda: dict()); print dis.dis(lambda:{})
@TokenMacGuy. Doh! I should have dis'd before making any claims. I stand corrected.
Having a large number of similarly named variables is typically not the way to go in the first place. dicts = {x: {} for x in ["a", "b", "c"]}.
1

Your first assignment assigns the same dictionary object to the variables dict_a, dict_b, and dict_c. It is equivalent to dict_c = {}; dict_b = dict_c; dict_a = dict_c.

Comments

1

As danben previously said, you're just copying the same dict into 3 variables, so that each one refers to the same object.

To get the behaviour you want, you should instantiate a different dict in each variable:

>>> dict_a, dict_b, dict_c = {}, {}, {}
>>> dict_c['hello'] = 'goodbye'
>>> print dict_a
{}
>>> print dict_b
{}
>>> print dict_c
{'hello': 'goodbye'}
>>>

1 Comment

Thanks, this was what I was intending to do when I stumbled upon this subject. Although its not an answer to the question, thanks very much.
0

I agree with what is said above. The key here is that, in Python, assignments represent references to the object. I was trying to grasp the concept myself and I think is it important to understand in which case a new object is created and when is the existing one changed.

In the example above, the line:

dict_c['hello'] = 'goodbye'

doesn't create a new object. It only changes the object which is referenced by dict_a, dict_b, and dict_c.

If, instead, you wrote:

dict_c = {'hello': 'goodbye'}

it would create a new object which would be referenced by dict_c. Dict_a and dict_b would still be pointing to the empty object.

In that case, if you run:

print dict_a
print dict_b
print dict_c

you would get:

{}
{}
{'hello': 'goodbye'}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.