为啥更改 dict2 内的嵌套 dict 会影响 dict1? [复制]
Posted
技术标签:
【中文标题】为啥更改 dict2 内的嵌套 dict 会影响 dict1? [复制]【英文标题】:Why do changes to a nested dict inside dict2 affect dict1? [duplicate]为什么更改 dict2 内的嵌套 dict 会影响 dict1? [复制] 【发布时间】:2018-10-30 22:03:29 【问题描述】:我不明白这些情况:
content = 'a': 'v': 1, 'b': 'v': 2
d1 = 'k1':
d2 = 'k2':
d1['k1'].update(content)
print(d1)
content['a']['v'] = 3
content['b']['v'] = 4
d2['k2'].update(content)
print(d2)
print(d1)
>>> 'k1': 'a': 'v': 1, 'b': 'v': 2
>>> 'k2': 'a': 'v': 3, 'b': 'v': 4
>>> 'k1': 'a': 'v': 3, 'b': 'v': 4
在上述情况下,在变量 content 更新后,d1 的内容发生了变化。
content = 'a': 1, 'b': 2
d1 = 'k1':
d2 = 'k2':
d1['k1'].update(content)
print(d1)
content['a'] = 3
content['b'] = 4
d2['k2'].update(content)
print(d2)
print(d1)
>>> 'k1': 'a': 1, 'b': 2
>>> 'k2': 'a': 3, 'b': 4
>>> 'k1': 'a': 1, 'b': 2
但是在这种情况下,即使变量 content 已更改,d1 也不会更改。我不明白为什么……有什么想法吗?
【问题讨论】:
我认为所有这些赞成票但没有 cmets/answers 是因为人们也认为这是一种奇怪的行为。 :P @MateenUlhaq 不是,这与dict
是可变对象而int
是不可变的事实有关。这使得 python 以不同的方式处理它们。如果内容是list
(可变),也会发生类似的事情。
第二个例子不是也改变了字典(content
)吗?
@MateenUlhaq 不,在第一个示例中,键指向 dict
,在第二个示例中,它们指向 int
。令人困惑的是这些字典的嵌套性质,但在后台,所有内容都由一堆一旦调用就会解析的指针组成。
@MateenUlhaq 如果我善于解释这一点,我会发布答案:)
【参考方案1】:
见shallow vs deep复制。
这里的副本是浅副本,因此第一级条目是副本,但嵌套结构是引用。
浅拷贝构造一个新的复合对象,然后(在可能的范围内)向其中插入对对象的引用 在原文中找到。 深拷贝构造一个新的复合对象,然后递归地将在中找到的对象的副本插入其中 原创。
【讨论】:
请不要重复回答。 我投票决定关闭它的价值。【参考方案2】:如果我们用一个简单的赋值替换update()
:
# d1['k1'].update(content)
d1['k1'] = content
我们得到:
'k1': 'a': 1, 'b': 2
'k2': 'a': 3, 'b': 4
'k1': 'a': 3, 'b': 4
(这与 update
在您的示例中所做的不同。)这是因为 update
接受一个可迭代对象(例如字典)并复制键值对内部。相当于做:
d1['k1'] = k: v for k, v in content.items()
当然,int
值是不可变的,因此它们的重新分配不会影响原始值。
【讨论】:
【参考方案3】:您的两个 sn-ps 之间的主要区别在于 content['a']['v'] = 3
与 content['a'] = 3
是完全不同的操作。在第一种情况下,您通过更改其v
键修改内部字典。在后一种情况下,您替换字典中的值而不修改它。
当一切都是字典时,这很令人困惑,所以让我们将字典替换为变量和类的实例:
class Person:
def __init__(self, name):
self.name = name
# these two variables are represent your `content` dict
a = Person('Andy') # this variable represents `'v': 1`
b = Person('Belle') # this variable represents `'v': 2`
# the equivalent of `d1['k1'].update(content)` is a simple assignment
k1_a = a
# and the equivalent of `content['a']['v'] = 3` is changing a's name
a.name = 'Aaron'
# because k1_a and a are the same Person instance, this is reflected in k1_a:
print(k1_a.name) # output: Aaron
这里要注意的关键点是
k1_a = a
不会复制 Person;类似于d1['k1'].update(content)
不会复制'v': 1
dict。
a.name = 'Aaron'
修改 Person;类似于content['a']['v'] = 3
修改内部字典的方式。
相当于您的第二个 sn-p 如下所示:
a = 'Andy'
b = 'Belle'
k1_a = a
a = 'Aaron'
print(k1_a) # output: Andy
这一次,没有对象被修改。我们所做的只是覆盖a
变量的值,这正是content['a'] = 3
覆盖您的dict 中a
键的值的方式。
如果您不希望内部 dicts 中的更改反映在其他 dicts 中,则必须使用 copy.deepcopy
复制它们:
import copy
content = 'a': 'v': 1, 'b': 'v': 2
d1 = 'k1':
d2 = 'k2':
d1['k1'].update(copy.deepcopy(content))
print(d1)
content['a']['v'] = 3
content['b']['v'] = 4
d2['k2'].update(copy.deepcopy(content))
print(d2)
print(d1)
# output:
# 'k1': 'a': 'v': 1, 'b': 'v': 2
# 'k2': 'a': 'v': 3, 'b': 'v': 4
# 'k1': 'a': 'v': 1, 'b': 'v': 2
【讨论】:
以上是关于为啥更改 dict2 内的嵌套 dict 会影响 dict1? [复制]的主要内容,如果未能解决你的问题,请参考以下文章
python 验证两个dicts dict1和dict2的名称。它会验证名称是否与小写字母不匹配。它删除了“Press Ente