我设置了dict2 = dict1。当我编辑dict2时,原来的dict1也改变了。为什么?

>>> dict1 = {"key1": "value1", "key2": "value2"}
>>> dict2 = dict1
>>> dict2["key2"] = "WHY?!"
>>> dict1
{'key2': 'WHY?!', 'key1': 'value1'}

当前回答

深度和简单的记忆方法:

当你执行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很慢,因为它递归地复制原始字典中的任何嵌套值,还需要额外的内存。

其他回答

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的元素(你是否将它指向一个列表?)也是副本。

我不怎么使用深度复制——编写需要它的代码通常是一种糟糕的实践(在我看来)。

在Python 2.7和3中创建字典副本的最佳和最简单的方法是…

创建一个简单(单层)字典的副本:

1. 使用dict()方法,而不是生成指向现有dict的引用。

my_dict1 = dict()
my_dict1["message"] = "Hello Python"
print(my_dict1)  # {'message':'Hello Python'}

my_dict2 = dict(my_dict1)
print(my_dict2)  # {'message':'Hello Python'}

# Made changes in my_dict1 
my_dict1["name"] = "Emrit"
print(my_dict1)  # {'message':'Hello Python', 'name' : 'Emrit'}
print(my_dict2)  # {'message':'Hello Python'}

2. 使用python字典内置的update()方法。

my_dict2 = dict()
my_dict2.update(my_dict1)
print(my_dict2)  # {'message':'Hello Python'}

# Made changes in my_dict1 
my_dict1["name"] = "Emrit"
print(my_dict1)  # {'message':'Hello Python', 'name' : 'Emrit'}
print(my_dict2)  # {'message':'Hello Python'}

创建一个嵌套的或复杂的字典的副本:

使用内置的复制模块,它提供了通用的浅拷贝和深拷贝操作。此模块在Python 2.7和3中都有

import copy

my_dict2 = copy.deepcopy(my_dict1)

你可以通过调用带有额外关键字参数的dict构造函数,一次复制和编辑新构造的副本:

>>> dict1 = {"key1": "value1", "key2": "value2"}
>>> dict2 = dict(dict1, key2="WHY?!")
>>> dict1
{'key2': 'value2', 'key1': 'value1'}
>>> dict2
{'key2': 'WHY?!', 'key1': 'value1'}

你也可以用字典理解来创建一个新字典。这避免了导入副本。

dout = dict((k,v) for k,v in mydict.items())

当然,在python >= 2.7中,你可以这样做:

dout = {k:v for k,v in mydict.items()}

但对于向后比较。,上面的方法更好。

Dict1是一个引用底层字典对象的符号。将dict1赋值给dict2只是赋值相同的引用。通过dict2符号更改键的值将更改底层对象,这也会影响dict1。这很令人困惑。

推断不可变值比推断引用要容易得多,所以尽可能地复制:

person = {'name': 'Mary', 'age': 25}
one_year_later = {**person, 'age': 26}  # does not mutate person dict

这在语法上是相同的:

one_year_later = dict(person, age=26)