4

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

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 的工作方式,我该如何找到解决方法?即使设置一个新的字典也会更新原来的字典。我的意思是:

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'}]

如果有人可以解释我为什么会发生这种情况,我将不胜感激。

4

5 回答 5

11

当您将 dict 添加到列表或将其分配给新变量时,您似乎希望将其复制,但这不是 Python 的操作方式。如果您分配一个 dict - 实际上,如果您分配任何对象 - 您并没有创建一个新对象,而是您只是给您的对象一个新名称。(一个对象可以有多个名称。)

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

如果你想复制你的对象,那么你可以这样做:

bar = dict(foo)

或者

bar = foo.copy()
于 2012-07-22T14:00:16.150 回答
5

简化:

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

b包含对a(并且dict是可变的)的“引用” - 所以如果a被修改然后a通过列表访问b,将显示修改后的a.

您必须显式创建 的副本a,在这种情况下可以这样做:

b = [dict(a)]

但是您应该查看copy模块copy.copy()copy.deepcopy()

于 2012-07-22T13:59:29.990 回答
3

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

import copy

someList.append(copy.copy(foo))
于 2012-07-22T13:58:56.260 回答
2

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

someList.append(foo)

不会创建 的副本foo并将其放在 上someList,它会将名称所指的对象附加到列表中。 foo

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

bar = foo

但这也不会创建副本。尤其

foo['x'] = 42

bar['x'] = 42

然后将对完全相同的对象进行操作。您可以通过打印对象的内存地址来验证这一点:

print id(foo), id(bar)

并看到它们是相同的。

如果您需要 Python 中的副本,则需要显式创建一个。根据您的需要,copy模块 -copy.copy()或者copy.deepcopy()- 将执行您想要的操作:

import copy
bar = copy.copy(foo)
print id(foo), id(bar)

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

于 2012-07-22T14:06:23.447 回答
1

字典是可变的,这意味着它们可以改变。这是因为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'}]
于 2012-07-22T13:58:12.903 回答