2015-02-06 15 views
0

由于一些限制,我需要创建一个对象的新副本以及所有属性的新副本以及其属性的属性等等。python:需要一个打破所有共享标识的深层拷贝

现有的deepcopy()是递归的,但是当被复制的树中的多个对象具有相同的起始标识时,它们也具有相同的结束标识(即使它们的结束标识与它们的起始标识不匹配)。

对于以下情况:

class A: 
    def __init__(self, x): 
    self.x = x 

v = A(1) 
o = [v, v] 

copy.deepcopy并执行以下操作:

dc_o = copy.deepcopy(o) 
assert dc_o[0] is not o[0] # new identity from the original 
assert dc_o[0] is dc_o[1] # but maintains identity within the copied tree 
assert dc_o[0] == dc_o[1] # ...as well as value 

但是,我需要的是:

r_dc_o = recursive_deepcopy(o) 
assert r_dc_o[0] is not o[0]  # new identity from the original 
assert r_dc_o[0] is not r_dc_o[1] # also new identity from elsewhere inside copy 
assert r_dc_o[0] == r_dc_o[1]  # while maintaining the same value 

我怎样才能做到这一点?

+1

即使它们不是相同的列表,等效列表的比较也是相等的。尝试与'is' /'不是'而不是'=='/'!='进行比较。 – Kevin 2015-02-06 17:02:08

+1

'1'和'2'将*总是*是同一个对象;他们被拘留。 'deepcopy'总是递归的;你只是没有以这种方式进行测试。 – 2015-02-06 17:03:06

+0

对不起,我的测试用例是错误的,我正在修复它。 – Nullpoet 2015-02-06 17:08:52

回答

1

的方式,没有 memoize的对象将是极其危险的完全自动化的递归deepcopy的 - 这将意味着你不能有任何形式与方式,这将使这些引用保存内部参考的对象在复制操作之后很有用(考虑具有“父”链接的对象或链接到共享注册表或类似资源的对象)。也就是说,如果你真的想这样做(并且你不应该 - 它会破坏很多很多通过操作的对象),你可以通过构造一个忽略尝试添加键的备忘字典来实现它,并且将其作为deepcopy()的第二个参数传递。

所以,我们在这里:

import copy 

class baddict(dict): 
    def __setitem__(self, k, v): 
     pass 

class A: 
    def __init__(self, x): 
    self.x = x 
    def __eq__(self, other): 
    self.x == other.x 

v = A(1) 
o = [v, v] 
r_dc_o = copy.deepcopy(o, baddict()) 
assert r_dc_o[0] is not r_dc_o[1] 
assert r_dc_o[0] == r_dc_o[1] 

我建议想为什么你需要这种行为,并试图想出一个更好的方式来完成它。即使是一个baddict的实现,只有当值是特定类的实例时,才会查看该值并跳过记忆,这比我们在此处执行的操作更安全。

+0

嗨查尔斯,对不起之前错误的测试用例。我已经修复了测试用例。我希望现在澄清我的问题。 – Nullpoet 2015-02-06 17:18:30

+0

啊。是的,这很清楚你的问题。 – 2015-02-06 17:22:23