我有一个类,其属性基于用户定义的字典初始化(使用 JSON 读入(:
class Knight(object):
def __init__(self, traits):
for k, v in traits.items():
self.__setattr__(k, v)
traitfile = json.load(open(input(), 'r'))
# Where the input file is e.g.
# {'helmet': 'horned',
# 'sword': 'big',
# 'words': ['Ni!', 'Peng', 'Neee-Wom!']}
当我实例化对象时,helmet
、sword
和words
按预期成为属性。但是,如果我随后更改实例属性,它似乎会影响最初初始化对象的原始字典:
tall_knight = Knight(traitfile)
print(tall_knight.words) # prints ['Ni!', 'Peng', 'Neee-Wom!']
print(traitfile['words']) # also prints ['Ni!', 'Peng', 'Neee-Wom!']
tall_knight.words.append('Ekke ekke!')
print(tall_knight.words) # prints ['Ni!', 'Peng', 'Neee-Wom!', 'Ekke ekke!'] as expected
print(traitfile['words']) # also prints ['Ni!', 'Peng', 'Neee-Wom!', 'Ekke ekke!'] NOT EXPECTED
我没想到对对象属性的更改会影响初始化它的字典。我认为实例化的全部意义在于实例是它自己的实例!这是怎么回事?!(我怎样才能阻止它?
您的问题是traitfile['words']
是一个列表,当您将其复制到tall_knight.words
时,您正在复制对列表的引用,而不是其中的值。所以当你修改tall_knight
中的列表时,你也会修改traitfile['words']
中的值。您可以通过使用以下copy.copy
(如果值可能嵌套,则copy.deepcopy
(复制对象中的值来解决此问题:
import copy()
class Knight(object):
def __init__(self, traits):
for k, v in traits.items():
self.__setattr__(k, copy.copy(v))
由于列表在 python 中是可变对象,因此当您创建对象时,引用在幕后将是相同的,因此您需要调用 list.copy((,它将创建一个具有不同引用的副本,然后您的更改将不会反映在原始文件中。
first_list = {"a":1, "b":[2,3,4]}
second_list = first_list
second_list["b"].append(34)
print("first one: ", first_list)
print("second one: ", second_list)
输出:
first one: {'a': 1, 'b': [2, 3, 4, 34]}
second one: {'a': 1, 'b': [2, 3, 4, 34]}
因此,避免更改为原始版本更好的方法是使用 copy 函数:second_list = first_list.copy((
根据您的情况包括更多内容,您还需要在更改对象之前创建副本:
import copy
class Knight(object):
def __init__(self, traits):
for k, v in traits.items():
self.__setattr__(k, copy.deepcopy(v))
traitfile = json.load(open(input(), 'r'))
以下是供参考的链接:可变和不可变数据类型