0

This is the code:

def init_dic(init):
    return {str(i):init for i in range(0,5)}

a = init_dic([])
print('Origin: ', a)

a['1'].append('test')
print('After append: ', a)

And the result:

Origin:  {'3': [], '4': [], '0': [], '1': [], '2': []}
After append:  {'3': ['test'], '4': ['test'], '0': ['test'], '1': ['test'], '2': ['test']}

But I expect the result should be:

Origin:  {'3': [], '4': [], '0': [], '1': [], '2': []}
After append:  {'3': [], '4': [], '0': [], '1': ['test'], '2': []}

Why this happens? I have no idea how so...

So if I want the correct result, how should I do to correct my code?

Mars Lee
  • 1,845
  • 5
  • 17
  • 37
  • 1
    Reading this, I wonder if you just want to use a `collections.defaultdict(list)` anyway. https://docs.python.org/2/library/collections.html#collections.defaultdict – kojiro Jun 03 '16 at 04:10

2 Answers2

3

problem is here:

def init_dic(init):
    return {str(i):init for i in range(0,5)}

returned dictionary will have values that are pointing to the same object in memory:

>>> a['1'] is a['2']
True

avoid this by making copies of init:

def init_dic(init):
    return {str(i):init[:] for i in range(0,5)}

Recommended reading:

http://docs.python-guide.org/en/latest/writing/gotchas/ https://docs.python.org/2.7/reference/datamodel.html#objects-values-and-types

Dmitry Tokarev
  • 1,851
  • 15
  • 29
1

All your dict values are references to the same list object. Appending to it will affect all of them. This problem will always arise when your init param is mutable. For immutable parameters (int, float, tuple, etc), it will work.

You could do the following (in case you know init will be a list):

def init_dic(init):
    return {str(i): init[:] for i in range(0,5)}  # use a copy

A more general approach would be to provide a factory (a 0-argument callable producing the actual value) as init and use as follows:

def init_dic(init):
    return {str(i): init() for i in range(0,5)}  # factory is called for each iteration

a = init_dic(lambda: [])
# a = init_dic(list)

As Kojiro points out, this then resembles a defaultdict, albeit an eager one and for a limited number of keys.

user2390182
  • 72,016
  • 6
  • 67
  • 89