在Python中,如何在_deepcopy__()的实现中调用copy.deepcopy?

在Python中,如何在_deepcopy__()的实现中调用copy.deepcopy?,python,copy,deep-copy,Python,Copy,Deep Copy,我想创建一个类,它可以提供一个属性列表,这些属性不是通过copy.deepcopy()进行深度复制的。例如: class CustomDeepcopy(object): a = SomeSimpleObject() b = SomeBigObject() def dont_deepcopy(self): return ['b'] def __deepcopy__(self,memo): #Somehow call copy.d

我想创建一个类,它可以提供一个属性列表,这些属性不是通过
copy.deepcopy()
进行深度复制的。例如:

class CustomDeepcopy(object):

    a = SomeSimpleObject()
    b = SomeBigObject()

    def dont_deepcopy(self):
        return ['b']

    def __deepcopy__(self,memo):
        #Somehow call copy.deepcopy(self) and have it  
        #deepcopy self.a but not self.b
        #
        #For example, this *almost* works, 
        for attr in self.dont_deepcopy():
            val = getattr(self,attr,None)
            if val is not None:
                 memo[id(val)]=val
        return copy.deepcopy(self,memo)

问题是,我不认为我可以从
\uuuuu deepcopy\uuuuu()
内部调用
copy.deepcopy()
,因为这会导致无限递归(因为
copy.deepcopy()
首先检查我的对象是否有
\uu deepcopy\uuuuu()
方法)。我有什么办法可以做到这一点吗

任何时候你实施一种特殊的方法(如
\uuuu getattr\uuuuuuu
\uuu deepcopy\uuuuuuuuu
\uu str\uuuuuuuuuu
等),你要么需要用super进入mro,要么使用原始方法的一些子集

我不完全清楚您是如何记忆属性的,但我将简化您的示例。假设您总是使用相同的a(并且它是不可变的,不需要复制),但是如果不这样,您希望复制b。(您可以将
a
b
直接传递给构造函数以创建新对象

class CustomDeepcopy(object):
    def __init__(self, a=None, b=None):
        if a:
            self.a = a
        if b:
            self.b = b

    a = SomeSimpleObject()
    b = SomeBigObject()

    @property
    def dont_deepcopy(self):
        return ['b']
    @property
    def deepcopy_attributes(self):
        return ['a']

    def __deepcopy__(self,memo):
        new_kwargs = dict((k, getattr(self, attr, None)) for attr in self.dont_deepcopy)
        for attr in self.deepcopy_attributes:
            new_kwargs[attr] = copy.deepcopy(getattr(self, attr, None))
        return self.__class__(**new_kwargs)

copy.deepcopy
只会在方法存在的情况下调用
\uuuuuu deepcopy\uuuuu
,我们可以通过保存
\uuuu deepcopy\uuuuu的值,调用
copy.deepcopy(…)
,然后在返回结果之前恢复
\uuuu deepcopy\uuuu
的值来避免这种情况:

class CustomDeepcopy(object):

    a = SomeSimpleObject()
    b = SomeBigObject()

    def dont_deepcopy(self):
        return ['b']

    def __deepcopy__(self,memo):
        for attr in self.dont_deepcopy():
            val = getattr(self,attr,None)
            if val is not None:
                 memo[id(val)]=val
        deepcopy_method = self.__deepcopy__
        self.__deepcopy__ = None
        result = copy.deepcopy(self,memo)
        self.__deepcopy__ = deepcopy_method
        return result

为什么要调用
deepcopy
,第一个参数是
self
方法返回
self
的deepcopy,对我没有进行deepcopy
self.b
deepcopy
的小更改进行模化。b只需要一个参数。您是浅层复制它们吗?
deepcopy
实际上需要两个参数,第一个是要进行deepcopy的对象,第二个是在中提到,但没有记录。如果你看源代码,它是一个字典,将对象的id映射到对象,对于已经被复制的对象。它正是我想在这里实现的目的,防止某些对象的深度复制。很好的问题——有一个非常类似的问题:快速检查一个对象,看看我能做什么做一个非常快速的deepcopy替换;如果没有,那么就做普通的deepcopy。遗憾的是,这不可能像描述的那样。在这种情况下,提高MRO的问题是deepcopy代码在静态方法
copy.deepcopy
中,而不是在
对象中。\uuuu deepcopy\uuuu
中。否则,您给出的答案是一个很好的解决方法,“但我只是希望能够使用deepcopy。@马吕斯现在检查一下答案,它应该涵盖了你要找的内容(或者至少解释一下如何使用它)谢谢。我看到这个解决方案的问题是它依赖于保持不变的init构造函数。我希望以后有人可以用完全不同的东西来覆盖它,而不是依赖于构造函数采用特定形式的事实。@marius这依赖于
\uu init\uuu
构造函数允许相同的k作为主体上的属性。任何人都可以对此类进行子类化,只要它接受kwargs并将kwargs推到super类,它就可以工作。否则,您可以创建一个单独的方法,如
\u constructor
,并使用它来构造实例。“任何人都可以子类化这个类,只要它接受kwargs并将kwargs推到super类,它就会工作”你是对的,我想我只是希望不要把把把kwargs推到super的要求强加给任何子类化这个类的人。不过这可能是唯一的方法。