4

My code will be more clear I think-

someList = list()
foo = {'a':'b'}
someList.append(foo)
print someList
>>> [{'a':'b'}]
defaultbazz = {'a':2, 'b':'t', 'c':'gg'}

for k, v in defaultbazz.iteritems():
    foo[k] = v

print someList
>>> [{'a': 2, 'c': 'gg', 'b': 't'}]

Shouldn't the last print be [{'a':'b'}]? I didn't updated the someList, I want it as is..

It's seems to me uninterpreted behavior..

But if that's how python works, how can I find workaround? Even setting a new dict updates the original one dict.. I mean:

someList = list()
foo = {'a':'b'}
someList.append(foo)
print someList
>>> [{'a':'b'}]
bar = foo
defaultbazz = {'a':2, 'b':'t', 'c':'gg'}

for k, v in defaultbazz.iteritems():
    bar[k] = v

print someList
>>> [{'a': 2, 'c': 'gg', 'b': 't'}]

I'll be thankful if someone can maybe explain me why it's happen..

eligro
  • 785
  • 3
  • 13
  • 23

5 Answers5

11

It looks like you are expecting your dict to be copied when you add it to a list or assign it to a new variable, but that is not how Python operates. If you assign a dict -- actually, if you assign any object -- you are not creating a new object, but instead you are simply giving your object a new name. (An object can have multiple names.)

So, when you edit your object under the new name, the single instance of that object changes, and that change is visible when you access the object through any name.

If you want to copy your object, then you can do this:

bar = dict(foo)

or

bar = foo.copy()
Andrew Gorcester
  • 19,595
  • 7
  • 57
  • 73
5

To simplify:

a = {2: 3}
b = [a]

b contains a "reference" to a (and is a dict which is mutable) - so if a is modified then accessing a via the list b, will display the modified a.

You have to explicitly create a copy of a, which can be done in this case as:

b = [dict(a)]

But you should look at the copy module for copy.copy() and copy.deepcopy()

Jon Clements
  • 138,671
  • 33
  • 247
  • 280
3

Dictionaries are mutable objects, hence the result of your script. I guess you want a new object, i.e. a copy of the original one:

import copy

someList.append(copy.copy(foo))
Vidul
  • 10,128
  • 2
  • 18
  • 20
2

Variables in Python are just names of objects. If you change the object from any name "attached" to it, you will see the changes from every other name. Python never creates copies automatically for you, in particular:

someList.append(foo)

doesn't create a copy of foo and put it on someList, it appends the object that the name foo refers to onto the list.

You can create a second name for this object

bar = foo

but this does not create a copy either. In particular

foo['x'] = 42

and

bar['x'] = 42

will then operate on exactly the same object. You can verify this by printing the memory address of the object:

print id(foo), id(bar)

and see that they are the same.

If you need a copy in Python, you'll need to create one explicitly. Depending on what you need, the copy module -- either copy.copy() or copy.deepcopy() -- will do what you want:

import copy
bar = copy.copy(foo)
print id(foo), id(bar)

should now print different memory locations.

DSM
  • 342,061
  • 65
  • 592
  • 494
thebjorn
  • 26,297
  • 11
  • 96
  • 138
1

Dicts are mutable, which means that they can change. It's because foo is inside of someList and you're changing foo in the for-loop. Take a look at this simple example:

a_dict = {'a':'b'}
a_list = [a_dict]
print a_list # [{'a':'b'}]

#change the dict
a_dict['a'] = 'c'
print a_list # [{'a':'c'}]
TankorSmash
  • 12,186
  • 6
  • 68
  • 106
  • Pass-by-reference is an entirely different thing. (Not my downvote though.) –  Jul 22 '12 at 14:04
  • 1
    Some days I wish it were impossible to downvote something without leaving a comment. It seems likely the downvote is because of the mention of pass-by-reference, but I guess we'll never know. – kojiro Jul 22 '12 at 14:05
  • For what it's worth, [here's how Python passes stuff](http://stackoverflow.com/a/986145/418413). – kojiro Jul 22 '12 at 14:10
  • Thanks guys for the heads up. I just removed the offending line. – TankorSmash Jul 22 '12 at 14:20