我设置了dict2 = dict1。当我编辑dict2时,原来的dict1也改变了。为什么?
>>> dict1 = {"key1": "value1", "key2": "value2"}
>>> dict2 = dict1
>>> dict2["key2"] = "WHY?!"
>>> dict1
{'key2': 'WHY?!', 'key1': 'value1'}
我设置了dict2 = dict1。当我编辑dict2时,原来的dict1也改变了。为什么?
>>> dict1 = {"key1": "value1", "key2": "value2"}
>>> dict2 = dict1
>>> dict2["key2"] = "WHY?!"
>>> dict1
{'key2': 'WHY?!', 'key1': 'value1'}
当前回答
python中的每个变量(比如dict1或str或__builtins__)都是指向机器内部某个隐藏的柏拉图式“对象”的指针。
如果您设置dict1 = dict2,您只需将dict1指向与dict2相同的对象(或内存位置,或任何您喜欢的类比)。现在,dict1引用的对象就是dict2引用的对象。
你可以检查:dict1是dict2应该是True。另外,id(dict1)应该与id(dict2)相同。
你需要dict1 = copy(dict2),或者dict1 = deepcopy(dict2)。
复制和深度复制的区别是什么?Deepcopy将确保dict2的元素(你是否将它指向一个列表?)也是副本。
我不怎么使用深度复制——编写需要它的代码通常是一种糟糕的实践(在我看来)。
其他回答
如果你的字典是映射类型,你不能.copy()它,但你可以
dict2 = dict1 | {}
它有点模糊,与copy.copy(dict1)相比,我不能说它的性能如何,但它非常简洁。
当你赋值dict2 = dict1时,你并没有创建一个dict1的副本,结果是dict2只是dict1的另一个名字。
要复制像字典这样的可变类型,使用copy模块的copy / deepcopy。
import copy
dict2 = copy.deepcopy(dict1)
Dict2 = dict1不复制字典。它只是为程序员提供了另一种方法(dict2)来引用同一个字典。
深度和简单的记忆方法:
当你执行dict2 = dict1时,dict2指向dict1。dict1和dict2都指向内存中的相同位置。这只是在python中使用可变对象时的正常情况。当你在python中使用可变对象时,你必须小心,因为它很难调试。
你不应该使用dict2 = dict1,而是应该使用python的copy模块中的copy(浅拷贝)和deepcopy方法来分离dict2和dict1。
正确的做法是:
>>> dict1 = {"key1": "value1", "key2": "value2"}
>>> dict2 = dict1.copy()
>>> dict2
{'key1': 'value1', 'key2': 'value2'}
>>> dict2["key2"] = "WHY?"
>>> dict2
{'key1': 'value1', 'key2': 'WHY?'}
>>> dict1
{'key1': 'value1', 'key2': 'value2'}
>>> id(dict1)
140641178056312
>>> id(dict2)
140641176198960
>>>
正如您可以看到的,dict1和dict2的id是不同的,这意味着它们都指向/引用内存中的不同位置。
此解决方案适用于具有不可变值的字典,但不适用于具有可变值的字典。
Eg:
>>> import copy
>>> dict1 = {"key1" : "value1", "key2": {"mutable": True}}
>>> dict2 = dict1.copy()
>>> dict2
{'key1': 'value1', 'key2': {'mutable': True}}
>>> dict2["key2"]["mutable"] = False
>>> dict2
{'key1': 'value1', 'key2': {'mutable': False}}
>>> dict1
{'key1': 'value1', 'key2': {'mutable': False}}
>>> id(dict1)
140641197660704
>>> id(dict2)
140641196407832
>>> id(dict1["key2"])
140641176198960
>>> id(dict2["key2"])
140641176198960
你可以看到,尽管我们对dict1应用了copy,但在dict2和dict1上,mutable的值都被更改为false,尽管我们只在dict2上更改了它。这是因为我们改变了dict1中可变dict部分的值。当我们在dict上应用复制时,它只会做一个浅复制,这意味着它将所有不可变的值复制到一个新的dict中,而不复制可变的值,但它会引用它们。
最终的解决方案是对dict1进行深度复制,以完全创建一个包含复制的所有值(包括可变值)的新dict。
>>>import copy
>>> dict1 = {"key1" : "value1", "key2": {"mutable": True}}
>>> dict2 = copy.deepcopy(dict1)
>>> dict2
{'key1': 'value1', 'key2': {'mutable': True}}
>>> id(dict1)
140641196228824
>>> id(dict2)
140641197662072
>>> id(dict1["key2"])
140641178056312
>>> id(dict2["key2"])
140641197662000
>>> dict2["key2"]["mutable"] = False
>>> dict2
{'key1': 'value1', 'key2': {'mutable': False}}
>>> dict1
{'key1': 'value1', 'key2': {'mutable': True}}
正如您所看到的,id是不同的,这意味着dict2完全是一个新的dict,其中包含dict1中的所有值。
当你想改变任何可变值而不影响原始字典时,需要使用Deepcopy。如果不是,你可以使用浅拷贝。Deepcopy很慢,因为它递归地复制原始字典中的任何嵌套值,还需要额外的内存。
虽然dict.copy()和dict(dict1)会生成一个副本,但它们只是浅副本。如果你想要一个深度拷贝,copy.deepcopy(dict1)是必需的。一个例子:
>>> source = {'a': 1, 'b': {'m': 4, 'n': 5, 'o': 6}, 'c': 3}
>>> copy1 = source.copy()
>>> copy2 = dict(source)
>>> import copy
>>> copy3 = copy.deepcopy(source)
>>> source['a'] = 10 # a change to first-level properties won't affect copies
>>> source
{'a': 10, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}
>>> copy1
{'a': 1, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}
>>> copy2
{'a': 1, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}
>>> copy3
{'a': 1, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}
>>> source['b']['m'] = 40 # a change to deep properties WILL affect shallow copies 'b.m' property
>>> source
{'a': 10, 'c': 3, 'b': {'m': 40, 'o': 6, 'n': 5}}
>>> copy1
{'a': 1, 'c': 3, 'b': {'m': 40, 'o': 6, 'n': 5}}
>>> copy2
{'a': 1, 'c': 3, 'b': {'m': 40, 'o': 6, 'n': 5}}
>>> copy3 # Deep copy's 'b.m' property is unaffected
{'a': 1, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}
关于浅拷贝和深拷贝,请参阅Python复制模块docs:
浅复制和深复制之间的区别只与复合对象(包含其他对象的对象,如列表或类实例)相关:
浅拷贝构造一个新的复合对象,然后(在可能的范围内)将对原始对象的引用插入其中。 深度复制构造一个新的复合对象,然后递归地将原始对象中的对象的副本插入其中。