-1

Actually, I don't know how to explain this question in a proper title. Any edition is welcome.

Let's just see the example.

# python 2.7.x
import collections
d = collections.defaultdict(int)
d['a'] = 2
d['b'] = 1
res = [d]* 2
res[0]['a'] -= 1
print res[1]
# => defaultdict(<type 'int'>, {'a': 1, 'b': 1})

I was wondering why it affects the res[1]?

rj487
  • 4,075
  • 6
  • 39
  • 80

3 Answers3

3

Because res is a list of 2 elements which are each the same object: d.

Scott Hunter
  • 46,905
  • 10
  • 55
  • 92
  • Then how do I rewrite it to make it unique? – rj487 Mar 21 '19 at 17:40
  • You need to instantiate several defaultdict: `res = [collections.defaultdict(int), collections.defaultdict(int)]` or even better: `res = [collections.defaultdict(int) for _ in range(2)]` – cglacet Mar 21 '19 at 17:49
  • @cglacet But that is not what the OP's code intends to do. The OP's code intends to initialize a `defaultdict` with certain values and *then* make a list of several copies of the `defaultdict`. Your suggestion would result in a list of several empty `defaultdict` instead. – blhsing Mar 21 '19 at 19:22
  • That's correct, in that case you'll need to use the [`copy`](https://docs.python.org/3.5/library/copy.html#module-copy) module. – cglacet Mar 21 '19 at 19:38
1

Instead of using the repeater operator *, which simply copies the reference to d, you can use a list comprehension with a copy of the d as the output in each iteration:

res = [d.copy() for _ in range(2)]

Demo: https://ideone.com/0gnmkV

blhsing
  • 77,832
  • 6
  • 59
  • 90
0

Because they point to the same object. You can see this by running

print(id(res[0]))
print(id(res[1]))

if you don't want them to mimic each other you can do a copy of the dictionary.

Victor Uriarte
  • 459
  • 4
  • 9