[英]Python: setting values of a list of nested dictionaries in class instances
I have a burning question that I just can't figure out. 我有一个亟待解决的问题,我只是想不通。 Let's say you have a class, and this class takes in as input a list of nested dictionaries.
假设您有一个类,该类将嵌套字典的列表作为输入。 It initializes one of the keys of each of these dictionaries with a new, empty dictionary.
它将使用新的空字典初始化每个词典的键之一。 Later, I want to set one of the nested values of an object in the list as something.
稍后,我想将列表中对象的嵌套值之一设置为某种值。 For some reason this seems to affect other objects in the list?
由于某种原因,这似乎会影响列表中的其他对象?
I know that's sounds very convoluted, so here's an example: 我知道这听起来很令人费解,所以这里有个例子:
class Tester():
def __init__(self, stuff):
# stuff is a list of dictionaries
self.stuff = stuff
# Each item in the list should be initialized to this dictionary
inside_init_dict = {'test': True}
for x in self.stuff:
x['info'] = inside_init_dict
if __name__ == '__main__':
new_stuff = [{'info': {}}, {'info': {}}, {'info': {}}]
mytest = Tester(new_stuff)
print(mytest.stuff)
# >>> [{'info': {'test': True}}, {'info': {'test': True}}, {'info': {'test': True}}]
# I want to just set a value in the nested dict of the first item in the list
mytest.stuff[0]['info']['test'] = False
# However, all items in the list change
print(mytest.stuff)
# >>> [{'info': {'test': False}}, {'info': {'test': False}}, {'info': {'test': False}}]
This happens on both Python 2 and 3. The only way I can get around this is to not use the separate variable "inside_init_dict", and directly set the initialized dictionary: 这在Python 2和Python 3上都发生。我可以解决的唯一方法是不使用单独的变量“ inside_init_dict”,而直接设置初始化的字典:
class Tester():
def __init__(self, stuff):
# stuff is a list of dictionaries
self.stuff = stuff
# Each item in the list should be initialized to this dictionary
for x in self.stuff:
x['info'] = {'test': True}
if __name__ == '__main__':
new_stuff = [{'info': {}}, {'info': {}}, {'info': {}}]
mytest = Tester(new_stuff)
print(mytest.stuff)
# >>> [{'info': {'test': True}}, {'info': {'test': True}}, {'info': {'test': True}}]
mytest.stuff[0]['info']['test'] = False
# This is what I want
print(mytest.stuff)
# >>> [{'info': {'test': False}}, {'info': {'test': True}}, {'info': {'test': True}}]
What's going on here? 这里发生了什么? I have tried setting the variable "inside_init_dict" in various places, like as a class variable or outside the class.
我尝试在各种地方设置变量“ inside_init_dict”,例如作为类变量或在类外部。 The issue still occurs.
问题仍然存在。
In the first example you create a single dictionary inside_init_dict
outside the loop and put it in multiple places. 在第一个示例中,您在循环外部创建了一个字典
inside_init_dict
,并将其放在多个位置。 Every element of the list gets that same inside_init_dict
. 列表中的每个元素都具有相同的
inside_init_dict
。 What you're seeing is not other objects in a list being affected, there's just one object being shown multiple times. 您所看到的并不是列表中的其他对象受到影响,只有一个对象被多次显示。
In the second example: 在第二个示例中:
for x in self.stuff:
x['info'] = {'test': True}
Now each x
gets its own dictionary. 现在,每个
x
都有自己的字典。 They all have the same value at first, but they are different instances, like identical twins. 一开始它们都具有相同的值,但是它们是不同的实例,就像同卵双胞胎一样。
This happens because dicts
are mutable , meaning that you can change their content without changing their identity. 发生这种情况是因为
dicts
是易变的 ,这意味着您可以更改其内容而无需更改其标识。 Here's a much simpler example of the behavior you're seeing: 这是您看到的行为的一个简单得多的示例:
my_dict = { "key" : "value" }
my_list = [ my_dict, my_dict ]
my_list[0]["key"] = "new_value"
print(my_list) # [ {"key" : "new_value"}, {"key": "new_value"} ]
Why this happens: 为什么会这样:
In the first line of this code, I create a new dictionary, {"key" : "value"}
, and assign the name my_dict
to it. 在此代码的第一行中,我创建了一个新字典
{"key" : "value"}
,并为其分配名称my_dict
。
In the second line, I create a list, whose zeroth and first element both point to my_dict
. 在第二行中,我创建一个列表,其第零个元素和第一个元素都指向
my_dict
。
In the third line, I access my_dict
(through my_list[0]
), and I mutate it: changing the value associated with "key"
. 在第三行中,我访问
my_dict
(通过my_list[0]
),并对它进行突变 :更改与"key"
关联的值。
In the fourth line, I check the value of my_list
. 在第四行中,我检查
my_list
的值。 Both the zeroth and the first element of my_list
still point to my_dict
-- and we've changed my_dict
. my_list
的第零个元素和第一个元素都仍指向my_dict
并且我们更改了my_dict
。 So the change is reflected in both elements of the list. 因此,更改将反映在列表的两个元素中。
One way to fix it: 解决它的一种方法:
Instead pointing to the same dictionary twice, create two dictionaries that have the same value: 而不是两次指向同一个字典,而是创建两个具有相同值的字典:
my_list = [ { "key" : "value" } , { "key" : "value" } ]
my_list[0]["key"] = "new_value"
print(my_list) # [ {"key" : "new_value"}, {"key": "value"} ]
Assign the keys to different copies of the inside_init_dict
dictionary instead of the same one: 将密钥分配给
inside_init_dict
词典的不同副本,而不是相同的副本:
...
inside_init_dict = {'test': True}
for x in self.stuff:
x['info'] = inside_init_dict.copy()
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.