0

Why in Python, use of n * [dict()] to create nested dictionary causes same dictionary object?

>>> d = [(111, 2222), (3333, 4444), (555, 666)]
>>> d
[(111, 2222), (3333, 4444), (555, 666)]
>>> x = len(d) * [dict().copy()][:]
>>> x
[{}, {}, {}]
>>> x[0]['x'] = 'u'
>>> x # All entries of x gets modified
[{'x': 'u'}, {'x': 'u'}, {'x': 'u'}]
>>> 
>>> x = [dict(), dict(), dict()]
>>> x
[{}, {}, {}]
>>> x[0]['x'] = 'u'
>>> x # only one entry of x gets modified
[{'x': 'u'}, {}, {}]
>>> 
amulllb
  • 3,036
  • 7
  • 50
  • 87
  • Here is how `dict.copy` copy dict. [Understanding dict.copy() - shallow or deep?](http://stackoverflow.com/questions/3975376/understanding-dict-copy-shallow-or-deep) – Kei Minagawa Mar 15 '14 at 01:30

1 Answers1

5

In x = len(d) * [dict().copy()][:], the dict function is run only once. Consequently, all three dictionaries are the same. If you want three different dictionaries, you need to run it three times, e.g.:

>>> x = [dict() for i in range(3)]
>>> x
[{}, {}, {}]
>>> x[0]['x'] = 'u'
>>> x
[{'x': 'u'}, {}, {}]
>>> 

More

Python cannot multiply a list until after it has created the list. Thus, when 3 * [dict()] is executed, dict is evaluated first and then the multiplication is performed. The same is true of 3*[int(1)] but notice a difference that may seem confusing at first:

>>> x = 3*[int(1)]
>>> x
[1, 1, 1]
>>> x[0] = 2
>>> x
[2, 1, 1]

Superficially, this might seem inconsistent with the case of the multiplied list of dictionaries. The difference here is that the assignment statement x[0] = 2 does not modify the properties of x[0]; it replaces x[0] with a new element. Consequently, the result is different.

The concept of replacement also applies to dictionaries. Consider:

>>> x = 3 * [dict()]
>>> x
[{}, {}, {}]
>>> x[0] = dict(x='u')
>>> x
[{'x': 'u'}, {}, {}]

Even thought the three dictionaries in x start out as the same, the statement x[0] = dict(x='u') replaces the first dictionary with a new one.

John1024
  • 109,961
  • 14
  • 137
  • 171
  • Then `int(1)` in `3*[int(1)]` will run only once? I don't know what happens applying `N*` to list. Please tell me if you know. – Kei Minagawa Mar 15 '14 at 04:36
  • @user2931409 Yes, `int` will run only once in that case. The list has to be created before multiplication can be performed. However, see the expanded answer for more on this. – John1024 Mar 15 '14 at 05:08
  • I did understand it! When I execute `x=3*[int(1)];x[0]=2` ,it simply overwrite `x[0]`. That's why `x[1]` and `x[2]` are not affected. I didn't notice that. Thanks for teaching me detail. – Kei Minagawa Mar 15 '14 at 05:42