【问题标题】:Shallow and deep copies for lists and dictionaries列表和字典的浅拷贝和深拷贝
【发布时间】:2014-12-23 20:54:14
【问题描述】:

我正在尝试更好地理解 Python 中的浅拷贝和深拷贝,尤其是在涉及字典和列表时。

假设我有一个字典列表,我想将特定键 ('a') 的值复制到不同键名 ('x') 下的不同字典列表中:

list_dict = [{'a': 1}, {'a': 2}]

dict1 = {}
dict1['x'] = {}
list1 = []

for entry in list_dict:
    dict1['x'] = entry['a']
    list1.append(dict1)

>>>print list1
[{'x': 2}, {'x': 2}]

显然,这不是我想要的。但是,我知道我可以为字典指定 .copy() 以创建浅拷贝:

for entry in list_dict:
    dict1['x'] = entry['a']
    list1.append(dict1.copy())

>>>print list1
[{'x': 1}, {'x': 2}]

即使它很浅,它也有效。现在,让我们让它变得有点不同——我不想把它复制到dict1['x'],而是复制到dict1['x']['y']

for entry in list_dict:
    dict1['x']['y'] = entry['a']
    list1.append(dict1.copy())

>>>print list1
[{'x': {'y': 2}}, {'x': {'y': 2}}]

回到第一格 - 它不起作用!所以,这是第一个问题 - 为什么它停止工作?

第二个问题是,为什么添加最后一行会起作用?

for entry in list_dict:
    dict1['x']['y'] = entry['a']
    list1.append(dict1.copy())
    dict1['x'] = {}

>>>print list1
[{'x': {'y': 1}}, {'x': {'y': 2}}]

非常感谢您!

附:我知道我可以先做import copy,然后再做copy.deepcopy(),但是我有兴趣了解为什么当我添加一层字典时浅拷贝会停止工作,以及为什么“重置”字典的解决方法会起作用。

【问题讨论】:

标签: python deep-copy shallow-copy


【解决方案1】:
for entry in list_dict:
    dict1['x']['y'] = entry['a']
    list1.append(dict1.copy())

>>>print list1
[{'x': {'y': 2}}, {'x': {'y': 2}}]

回到第一格 - 它不起作用!所以,这是第一个问题 - 为什么它停止工作?

因为,您现在拥有 三个 字典:

  1. {'x': {'y': 2}}

  2. {'x': {'y': 2}}

  3. {'y': 2}

    其中只有两个被“复制”(1 和 2)。它们都引用 3。3 中的变化反映在 1 和 2 中。


第二个问题是,为什么添加最后一行会起作用?

for entry in list_dict:
    dict1['x']['y'] = entry['a']
    list1.append(dict1.copy())
    dict1['x'] = {}

>>>print list1
[{'x': {'y': 1}}, {'x': {'y': 2}}]

因为,您现在在每次迭代(使用{})上创建一个新字典,然后您对其进行更改。您已经在初始化代码中创建了第一个。您不会更改列表中旧词典的引用。只有即将插入的那个。

未来提示:在这种情况下,为了帮助您遵循代码,最好的做法是使用调试模式并逐步执行程序。或者做懒人做的事情,在迭代过程中简单地在对象中打印,看看它们的值是什么。

【讨论】:

  • 我想我拿到了第一部分,谢谢!但是,仍然在为第二个而苦苦挣扎。为什么创建这个新的空字典不会清空浅拷贝?换句话说,为什么dict1['x']['y'] = entry['a'] 会改变list1 的内容,而dict1['x'] = {} 不会呢?是否只是因为第一个有 2 级嵌套,而第二个没有?但是,如果我这样做 dict1['x'] = {'a': 123} - 结果是 'y' 值也会被保存......
  • dict1['x'] -> 将dict1 中的任何内容都给我'x' 键下。 dict1['x']['y] -> 给我dict1'x' 下的任何内容,然后在该结果中给我'y' 下的任何内容。所以,你在第一种情况下所做的直接改变了dict1。你在第二种情况下所做的改变了对象 dict1 的引用。您可能还注意到,虽然'x'dict1 中的键,但'y'dict1 中的对象中的键。您可以自己尝试使用print dict1.keys() 打印dict1 中的所有键,您会看到y 不存在。
猜你喜欢
  • 2012-04-12
  • 2015-01-13
  • 1970-01-01
  • 2012-04-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-20
相关资源
最近更新 更多