Python: 在 class 个实例中设置嵌套字典列表的值
Python: setting values of a list of nested dictionaries in class instances
我有一个我无法弄清楚的紧迫问题。假设您有一个 class,这个 class 将嵌套字典列表作为输入。它用一个新的空字典初始化每个字典的一个键。后来,我想将列表中对象的嵌套值之一设置为某物。出于某种原因,这似乎会影响列表中的其他对象?
我知道这听起来很复杂,所以这里有一个例子:
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}}]
这发生在 Python 2 和 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}}]
这是怎么回事?我试过在不同的地方设置变量 "inside_init_dict",比如作为 class 变量或在 class 之外。问题仍然存在。
将键分配给 inside_init_dict
字典的不同副本,而不是同一字典:
...
inside_init_dict = {'test': True}
for x in self.stuff:
x['info'] = inside_init_dict.copy()
在第一个示例中,您在循环外创建了一个字典 inside_init_dict
并将其放在多个位置。列表中的每个元素都得到相同的 inside_init_dict
。您看到的不是列表中的其他对象受到影响,只是一个对象被多次显示。
在第二个例子中:
for x in self.stuff:
x['info'] = {'test': True}
现在每个 x
都有自己的字典。它们最初都具有相同的值,但它们是不同的实例,就像同卵双胞胎。
发生这种情况是因为 dicts
是 mutable,这意味着您可以在不更改其身份的情况下更改其内容。这是您所看到的行为的一个更简单的示例:
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"} ]
为什么会这样:
在这段代码的第一行,我创建了一个新字典 {"key" : "value"}
,并为其分配了名称 my_dict
。
在第二行,我创建了一个列表,它的第零个和第一个元素 both 指向 my_dict
.
在第三行,我访问了my_dict
(通过my_list[0]
),我改变它:改变与[=18=关联的值].
在第四行,我检查了my_list
的值。 my_list
的第零个和第一个元素仍然指向 my_dict
-- 我们已经更改了 my_dict
。所以变化反映在列表的两个元素中。
一种修复方法:
创建两个具有相同值的字典,而不是指向同一个字典两次:
my_list = [ { "key" : "value" } , { "key" : "value" } ]
my_list[0]["key"] = "new_value"
print(my_list) # [ {"key" : "new_value"}, {"key": "value"} ]
我有一个我无法弄清楚的紧迫问题。假设您有一个 class,这个 class 将嵌套字典列表作为输入。它用一个新的空字典初始化每个字典的一个键。后来,我想将列表中对象的嵌套值之一设置为某物。出于某种原因,这似乎会影响列表中的其他对象?
我知道这听起来很复杂,所以这里有一个例子:
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}}]
这发生在 Python 2 和 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}}]
这是怎么回事?我试过在不同的地方设置变量 "inside_init_dict",比如作为 class 变量或在 class 之外。问题仍然存在。
将键分配给 inside_init_dict
字典的不同副本,而不是同一字典:
...
inside_init_dict = {'test': True}
for x in self.stuff:
x['info'] = inside_init_dict.copy()
在第一个示例中,您在循环外创建了一个字典 inside_init_dict
并将其放在多个位置。列表中的每个元素都得到相同的 inside_init_dict
。您看到的不是列表中的其他对象受到影响,只是一个对象被多次显示。
在第二个例子中:
for x in self.stuff:
x['info'] = {'test': True}
现在每个 x
都有自己的字典。它们最初都具有相同的值,但它们是不同的实例,就像同卵双胞胎。
发生这种情况是因为 dicts
是 mutable,这意味着您可以在不更改其身份的情况下更改其内容。这是您所看到的行为的一个更简单的示例:
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"} ]
为什么会这样:
在这段代码的第一行,我创建了一个新字典 {"key" : "value"}
,并为其分配了名称 my_dict
。
在第二行,我创建了一个列表,它的第零个和第一个元素 both 指向 my_dict
.
在第三行,我访问了my_dict
(通过my_list[0]
),我改变它:改变与[=18=关联的值].
在第四行,我检查了my_list
的值。 my_list
的第零个和第一个元素仍然指向 my_dict
-- 我们已经更改了 my_dict
。所以变化反映在列表的两个元素中。
一种修复方法:
创建两个具有相同值的字典,而不是指向同一个字典两次:
my_list = [ { "key" : "value" } , { "key" : "value" } ]
my_list[0]["key"] = "new_value"
print(my_list) # [ {"key" : "new_value"}, {"key": "value"} ]