为什么我将一个项目添加到字典中的一个列表中,而其他所有列表也会更改?

时间:2016-06-03 04:00:19

标签: python

这是代码:

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)

结果:

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

但我希望结果应该是:

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

为什么会这样?我不知道怎么回事......

所以如果我想要正确的结果,我该如何纠正我的代码?

2 个答案:

答案 0 :(得分:3)

问题在这里:

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

返回的字典将具有指向内存中相同对象的值:

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

通过复制init:

来避免这种情况
def init_dic(init):
    return {str(i):init[:] for i in range(0,5)}

推荐阅读:

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

答案 1 :(得分:1)

您的所有dict值都是对同一list个对象的引用。附加到它将影响所有这些。当init param可变时,将始终出现此问题。对于不可变参数(int,float,tuple等),它将起作用。

您可以执行以下操作(如果您知道init将是list):

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

更通用的方法是将工厂(产生实际值的0参数可调用)提供为init并使用如下:

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)

正如小次郎所指出的那样,这就像一个defaultdict,虽然是一个渴望和有限数量的钥匙。