-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,476
  • 6
  • 47
  • 88

3 Answers3

3

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

Scott Hunter
  • 48,888
  • 12
  • 60
  • 101
  • 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
  • 91,368
  • 6
  • 71
  • 106
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
  • 479
  • 4
  • 9