我设置了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'}
当前回答
对于嵌套的字典,不要使用dict(srcData)或srcData.copy()或{**srcData},因为如果你改变了秒级或更多,它也会修改源字典
srcData = {
'first': {
'second': 'second Value'
}
}
newData = dict(srcData) # srcData.copy() or {**srcData}
newData['first']['second'] = 'new Second Value'
print(srcData)
print(newData)
# it will print
# srcData: {'first': {'second': 'new Second Value'}}
# newData:{'first': {'second': 'new Second Value'}}
# but it should be
# srcData: {'first': {'second': 'second Value'}}
# newData:{'first': {'second': 'new Second Value'}}
deepcopy的另一个选择是使用json技巧,如Javascript json .parse(json .stringify(obj))
import json
srcData = {'first': {'second': 'second Value'}}
newData = json.loads(json.dumps(srcData))
newData['first']['second'] = 'new Second Value'
print(srcData)
print(newData)
# srcData: {'first': {'second': 'second Value'}}
# newData: {'first': {'second': 'new Second Value'}}
其他回答
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)
你也可以用字典理解来创建一个新字典。这避免了导入副本。
dout = dict((k,v) for k,v in mydict.items())
当然,在python >= 2.7中,你可以这样做:
dout = {k:v for k,v in mydict.items()}
但对于向后比较。,上面的方法更好。
正如其他人解释的那样,内置字典不能做你想做的事情。但是在Python2(可能还有python3)中,你可以很容易地创建一个ValueDict类,使用=进行复制,这样你就可以确保原始的类不会改变。
class ValueDict(dict):
def __ilshift__(self, args):
result = ValueDict(self)
if isinstance(args, dict):
dict.update(result, args)
else:
dict.__setitem__(result, *args)
return result # Pythonic LVALUE modification
def __irshift__(self, args):
result = ValueDict(self)
dict.__delitem__(result, args)
return result # Pythonic LVALUE modification
def __setitem__(self, k, v):
raise AttributeError, \
"Use \"value_dict<<='%s', ...\" instead of \"d[%s] = ...\"" % (k,k)
def __delitem__(self, k):
raise AttributeError, \
"Use \"value_dict>>='%s'\" instead of \"del d[%s]" % (k,k)
def update(self, d2):
raise AttributeError, \
"Use \"value_dict<<=dict2\" instead of \"value_dict.update(dict2)\""
# test
d = ValueDict()
d <<='apples', 5
d <<='pears', 8
print "d =", d
e = d
e <<='bananas', 1
print "e =", e
print "d =", d
d >>='pears'
print "d =", d
d <<={'blueberries': 2, 'watermelons': 315}
print "d =", d
print "e =", e
print "e['bananas'] =", e['bananas']
# result
d = {'apples': 5, 'pears': 8}
e = {'apples': 5, 'pears': 8, 'bananas': 1}
d = {'apples': 5, 'pears': 8}
d = {'apples': 5}
d = {'watermelons': 315, 'blueberries': 2, 'apples': 5}
e = {'apples': 5, 'pears': 8, 'bananas': 1}
e['bananas'] = 1
# e[0]=3
# would give:
# AttributeError: Use "value_dict<<='0', ..." instead of "d[0] = ..."
请参考这里讨论的左值修改模式:Python 2.7 -用于左值修改的干净语法。关键的观察是,str和int在Python中表现为值(即使它们实际上是不可变的对象)。在观察的同时,请注意str或int并没有什么神奇的特殊之处。dict可以以几乎相同的方式使用,我可以想到ValueDict有意义的许多情况。
使用for循环进行复制:
orig = {"X2": 674.5, "X3": 245.0}
copy = {}
for key in orig:
copy[key] = orig[key]
print(orig) # {'X2': 674.5, 'X3': 245.0}
print(copy) # {'X2': 674.5, 'X3': 245.0}
copy["X2"] = 808
print(orig) # {'X2': 674.5, 'X3': 245.0}
print(copy) # {'X2': 808, 'X3': 245.0}
在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)