如何创建与原对象不关联的Python对象副本?

3 投票
2 回答
1776 浏览
提问于 2025-04-17 20:01

(使用 Python 2.7)

我想创建一些模板对象的副本,之后再填充内容。为了简单起见,我试着这样做:

template={'thing1':'','thing2':'','thing3':''}
for number in some_list:
    pile[number]=template

但是后来我这样做的时候:

pile[1]['thing1']='blahblah'

结果也变成了:

print pile[2]['thing1']
'blahblah'
print template['thing1']
'blahblah'

我想要的是让

pile[1]['thing1']='blahblah'

保持不变,这样

print pile[2]['thing1']
''

而我知道问题出在我说的

pile[number]=template

这句话上,这意味着 pile[1] 是模板,pile[2] 也是模板。 (我今天在工作时才完全意识到这一点……我还大声重复了好几遍,才慢慢理解这个道理……这就是 Python 的 工作原理,对吧?我感觉我刚加入了 Python 的大家庭。我最开始用的是 MATLAB,所以请不要对我太苛刻。)

所以我想可能有两种方法可以解决这个问题——一种是创建与原始对象没有关联的对象副本,或者类似的东西,这可能非常简单和明显。还有可能有另一种方法是针对字典的,比如初始化键之类的。我主要对第一种答案感兴趣,因为这能帮助我更好地理解 Python 是如何 工作的,不过第二种答案也不错。谢谢 :)

2 个回答

3

这是我最初的解决方案

import copy

template = {1:''}
d = {}

for n in xrange(10):
    d[n] = copy.deepcopy(template)

不过我更喜欢Pavel的方案。

4

制作字典的浅拷贝最简单的方法就是使用字典的 copy 方法:

In [1]: template = {'thing1': '', 'thing2': '', 'thing3': ''}

In [2]: apile = template.copy()

In [3]: apile['thing1'] = 1

In [4]: apile
Out[4]: {'thing1': 1, 'thing2': '', 'thing3': ''}

In [5]: template
Out[5]: {'thing1': '', 'thing2': '', 'thing3': ''}

 

如果你想制作列表的浅拷贝,可以对整个列表进行切片:

copied_list = original_list[:]

 

如果你需要克隆其他类型的对象,或者需要对字典中的字典(或者字典中的列表,或者其他可变对象)进行深拷贝,你应该使用 copy 模块: http://docs.python.org/2/library/copy.html

copy.copy(x)

返回 x 的浅拷贝。

copy.deepcopy(x)

返回 x 的深拷贝。

浅拷贝和深拷贝的区别主要在于复合对象(包含其他对象的对象,比如列表或类实例):

  • 浅拷贝会构建一个新的复合对象,然后尽可能地将原始对象中的引用插入到这个新对象中。
  • 深拷贝会构建一个新的复合对象,然后递归地将原始对象中的对象的拷贝插入到这个新对象中。

 

关于你提到的第二种方法:当然,你可以从另一个字典创建一个字典,这样它就是一个拷贝:

In [23]: p = dict(template)

In [24]: p['thing1'] = 1

In [25]: template
Out[25]: {'thing1': '', 'thing2': '', 'thing3': ''}

In [26]: p
Out[26]: {'thing1': 1, 'thing2': '', 'thing3': ''}

撰写回答