如何在python中复制类实例?

时间:2018-01-19 10:23:34

标签: python class deep-copy

我想在python中创建一个类实例的副本。我试过copy.deepcopy,但收到错误消息:

  

RuntimeError:只有用户明确创建的变量(图形离开)才支持深度复制协议

假设我有类似的东西:

class C(object):
    def __init__(self,a,b, **kwargs):
        self.a=a
        self.b=b
        for x, v in kwargs.items():
            setattr(self, x, v)

c = C(4,5,'r'=2)
c.a = 11
del c.b

现在我想制作c的相同深度副本,有一种简单的方法吗?

3 个答案:

答案 0 :(得分:4)

是的,您可以使用deepcopy制作类实例的副本:

from copy import deepcopy

c = C(4,5,'r'=2)
d = deepcopy(c)

这会创建类实例的副本' c'在' d'

答案 1 :(得分:4)

实现这一目标的一种方法是在__copy__类中实施C,如下所示:

class A:
    def __init__(self):
        self.var1 = 1
        self.var2 = 2
        self.var3 = 3

class C(A):
    def __init__(self, a=None, b=None, **kwargs):
        super().__init__()
        self.a = a
        self.b = b
        for x, v in kwargs.items():
            setattr(self, x, v)

    def __copy__(self):
        self.normalizeArgs()
        return C(self.a, self.b, kwargs=self.kwargs)

    # THIS IS AN ADDITIONAL GATE-KEEPING METHOD TO ENSURE 
    # THAT EVEN WHEN PROPERTIES ARE DELETED, CLONED OBJECTS
    # STILL GETS DEFAULT VALUES (NONE, IN THIS CASE)
    def normalizeArgs(self):
        if not hasattr(self, "a"):
            self.a      = None
        if not hasattr(self, "b"):
            self.b      = None
        if not hasattr(self, "kwargs"):
            self.kwargs = {}

cMain   = C(a=4, b=5, kwargs={'r':2})

del cMain.b
cClone  = cMain.__copy__()

cMain.a = 11

del  cClone.b
cClone2 = cClone.__copy__()

print(vars(cMain))
print(vars(cClone))
print(vars(cClone2))

enter image description here

答案 2 :(得分:1)

我大部分时间都弄清楚了。我无法克服的唯一问题是为所有类知道一组可接受的初始化参数(__init__的参数)。所以我必须做出以下两个假设:

1)我有一组类C的默认参数,我称之为argsC。 2)C中的所有对象都可以用空参数初始化。

在哪种情况下我可以 的第一: 从我要复制C的实例初始化类c的新实例:

c_copy = c.__class__(**argsC)

<强>第二: 浏览c的所有属性,并将属性c_copy设置为c

属性的副本
for att in c.__dict__:
    setattr(c_copy, att, object_copy(getattr(c,att)))

其中object_copy是我们正在构建的函数的递归应用程序。

过去: 删除c_copy中的所有属性,但不删除c中的所有属性:

for att in c_copy.__dict__:
    if not hasattr(c, att):
        delattr(c_copy, att)

把这一切放在一起我们有:

import copy

def object_copy(instance, init_args=None):
    if init_args:
        new_obj = instance.__class__(**init_args)
    else:
        new_obj = instance.__class__()
    if hasattr(instance, '__dict__'):
        for k in instance.__dict__ :
            try:
                attr_copy = copy.deepcopy(getattr(instance, k))
            except Exception as e:
                attr_copy = object_copy(getattr(instance, k))
            setattr(new_obj, k, attr_copy)

        new_attrs = list(new_obj.__dict__.keys())
        for k in new_attrs:
            if not hasattr(instance, k):
                delattr(new_obj, k)
        return new_obj
    else:
        return instance

所以把它们放在一起我们有:

argsC = {'a':1, 'b':1}
c = C(4,5,r=[[1],2,3])
c.a = 11
del c.b
c_copy = object_copy(c, argsC)
c.__dict__
  

{'a':11,'r':[[1],2,3]}

c_copy.__dict__
  

{'a':11,'r':[[1],2,3]}

c.__dict__
  

{'a':11,'r':[[1,33],2,3]}

c_copy.__dict__
  

{'a':11,'r':[[1],2,3]}

这是期望的结果。如果可以,它使用deepcopy,但对于引发异常的情况,它可以不用。