如何创建与原对象不关联的Python对象副本?
(使用 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': ''}