为什么更新附加到列表的字典会更改列表?

时间:2012-07-22 13:51:09

标签: python arrays dictionary

我认为我的代码会更清晰 -

someList = list()
foo = {'a':'b'}
someList.append(foo)
print someList
>>> [{'a':'b'}]
defaultbazz = {'a':2, 'b':'t', 'c':'gg'}

for k, v in defaultbazz.iteritems():
    foo[k] = v

print someList
>>> [{'a': 2, 'c': 'gg', 'b': 't'}]

最后一次打印不应该是[{'a':'b'}]吗?我没有更新someList,我希望它原样..

在我看来,这是一种未被解释的行为。

但如果这就是python的工作方式,我该如何找到解决方法?即使设置一个新的dict也会更新原来的dict ..我的意思是:

someList = list()
foo = {'a':'b'}
someList.append(foo)
print someList
>>> [{'a':'b'}]
bar = foo
defaultbazz = {'a':2, 'b':'t', 'c':'gg'}

for k, v in defaultbazz.iteritems():
    bar[k] = v

print someList
>>> [{'a': 2, 'c': 'gg', 'b': 't'}]

如果有人能解释我为何会发生这种情况,我将感激不尽。

5 个答案:

答案 0 :(得分:11)

当你将dict添加到列表或将其分配给新变量时,看起来你期望复制你的dict,但这不是Python的运作方式。如果你指定一个字典 - 实际上,如果你指定任何一个对象 - 你不是在创建一个新对象,而是只是给你的对象一个新的名字。 (一个对象可以有多个名称。)

因此,当您使用新名称编辑对象时,该对象的单个实例会更改,并且当您通过任何名称访问该对象时,该更改都是可见的。

如果要复制对象,则可以执行以下操作:

bar = dict(foo)

bar = foo.copy()

答案 1 :(得分:5)

简化:

a = {2: 3}
b = [a]

b包含a的“引用”(并且是dict,它是可变的) - 因此,如果a被修改,则通过a访问b列表a将显示修改后的a

您必须明确创建b = [dict(a)] 的副本,在这种情况下可以这样做:

copy

但您应该查看copy.copy()copy.deepcopy()

的{{1}}模块

答案 2 :(得分:3)

字典是mutable个对象,因此是脚本的结果。 我想你想要一个新的对象,即原始对象的copy

import copy

someList.append(copy.copy(foo))

答案 3 :(得分:2)

Python中的变量只是对象的名称。如果您将对象从“附加”的任何名称更改为它,您将看到每个其他名称的更改。 Python从不为您自动创建副本,特别是:

someList.append(foo)

没有创建foo的副本并将其放在someList上,它会在对象附加名称 {{1} }指的是列表。

您可以为此对象创建第二个名称

foo

但这也不会创建副本。特别是

bar = foo

foo['x'] = 42
然后

将在完全相同的对象上运行。您可以通过打印对象的内存地址来验证这一点:

bar['x'] = 42

并且看到它们是相同的。

如果您需要Python中的副本,则需要明确创建一个副本。根据您的需要,print id(foo), id(bar) 模块 - copycopy.copy() - 可以满足您的需求:

copy.deepcopy()

现在应该打印不同的内存位置。

答案 4 :(得分:1)

Dicts是可变的,这意味着它们可以改变。这是因为foo位于someList内,而您在foo中正在更改for-loop。看看这个简单的例子:

a_dict = {'a':'b'}
a_list = [a_dict]
print a_list # [{'a':'b'}]

#change the dict
a_dict['a'] = 'c'
print a_list # [{'a':'c'}]