Python-从字典初始化的更改对象属性会影响原始字典吗?

时间:2020-06-29 01:27:46

标签: python python-3.x dictionary

我有一个具有基于用户定义的字典(使用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!']}

实例化对象时,helmetswordwords成为预期的属性。但是,如果我再更改一个实例属性,似乎会影响最初从中初始化对象的原始字典:

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

我没想到对对象属性的更改会影响初始化它的字典。我认为实例化的全部要点是实例是它自己的实例!这里发生了什么?! (我该如何阻止它?)

2 个答案:

答案 0 :(得分:4)

您的问题是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))

答案 1 :(得分:0)

由于list是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]}

因此最好避免使用原始功能,即使用复制功能: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'))

以下是参考链接:Mutable and Immutable datatypes