如何在python中复制类实例?

如何在python中复制类实例?,python,class,deep-copy,Python,Class,Deep Copy,我想用python复制一个类实例。我尝试了copy.deepcopy,但收到了错误消息: RuntimeError:目前只有用户显式创建的变量(图叶)支持deepcopy协议 那么假设我有这样的东西: class C(object): def __init__(self,a,b, **kwargs): self.a=a self.b=b for x, v in kwargs.items(): setattr(self

我想用python复制一个类实例。我尝试了
copy.deepcopy
,但收到了错误消息:

RuntimeError:目前只有用户显式创建的变量(图叶)支持deepcopy协议

那么假设我有这样的东西:

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
完全相同的深度副本,有没有简单的方法?

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

from copy import deepcopy

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

这将在“d”中创建类实例“c”的副本。

一种方法是在
c
类中实现
\uuuuuuuuuuuuuu
,如下所示:

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))

我基本上已经弄明白了。我唯一无法克服的问题是知道所有类的一组可接受的初始化参数(用于
的参数)。因此,我必须做出以下两个假设:

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

那样的话我可以 首先: 从我要复制的类的实例中初始化类的新实例
C

c_copy = c.__class__(**argsC)
for att in c_copy.__dict__:
    if not hasattr(c, att):
        delattr(c_copy, att)
: 检查
c
的所有属性,并将属性
c\u copy
设置为
c

for att in c.__dict__:
    setattr(c_copy, att, object_copy(getattr(c,att)))
其中,
object\u copy
是我们正在构建的函数的递归应用程序

最后一次: 删除
c\u copy
中的所有属性,但不删除
c
中的所有属性:

c_copy = c.__class__(**argsC)
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__
综上所述,我们有:

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]}

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

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

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


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

Yes。肯定覆盖
\uuuu复制\uuuuu
dunder。或者
\uuuu deepcopy\uuuuu
一个,具体取决于您的需要。是的,您可以使用
copy.deepcopy
。所以只要
c2=copy.deepcopy(c)
然后
vars(c2)={'a':11,'r':2}
vars(c)={'a':11,'r':2}
但是您报告的回溯不会由您给出的类定义生成…@cᴏʟᴅsᴘᴇᴇᴅ 注意,在这种情况下不需要这样做。
copy
模块将处理那些没有定义
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。。。好。。。那么简历是“离题”吗?我已经投票了。@juanpa.arrivillaga是的,事实上我正试图复制
torch.nn.Module
的一个元类,但这有点复杂,所以我在这里给出一个简单的例子。只是说在我的情况下,
deepcopy
不起作用,所以我想要另一个解决方案。我特别提到这对我不起作用。因为在我的例子中,
deepcopy
给出了一个错误。我特别不想要一个使用
deepcopy
的解决方案。我是在谷歌这里被指示搜索“如何deepcopy一个类的实例”的,这对我很有用。因此,我必须向上投票…
deepcopy
使用
pickle
,它在某些对象上会中断:
TypeError:cannotpickle pygame.Surface对象
——这正是我在这里搜索的解决方法。所以这对我不起作用。这不起作用,我得到了错误'9 def\u copy\uuuu(self):-->10关键字args=vars(self)['kwargs']11返回C(self.a,self.b,kwargs=keywordArgs)12关键字错误:'kwargs'`即使在我删除一个变量后也不应该起作用。因此,在执行
delc.a
之后,我应该能够执行
c\u prime=c.\uu copy\uuu()
。它还应该深度复制参数。因此,如果
c.a==[1,2]
我不应该让
c.a==c_prime.a
运行。但这并不能解决我的问题,因为在上面提到的其他问题中。如果我在脚本末尾添加以下行:
cClone=cMain.\uu copy\uuu()
,(即在
del
行之后),那么我会得到以下错误:
AttributeError:'C'对象没有属性“b”
如果我将您的行
cMain=C(a=4,b=5,kwargs={'r':2})交换给行
cMain=C,它也不起作用(4,5,'r'=2)
正如我在问题中所说。