如何在Python中“覆盖”deepcopy?

时间:2010-06-14 11:01:14

标签: python sqlalchemy deep-copy

我想为给定的SQLAlchemy映射类重写__deepcopy__,以便它忽略任何SQLA属性,但深入复制该类的其他所有内容。

我并不是特别熟悉覆盖任何Python的内置对象,但我对我想要的东西有所了解。

让我们创建一个使用SQLA映射的非常简单的类User

class User(object):
    def __init__(self, user_id=None, name=None):
        self.user_id = user_id
        self.name = name

我已经使用dir()来查看映射之前和之后的SQLAlchemy特定属性,并且我找到了_sa_class_manager_sa_instance_state

Questions
只要那些是唯一的,在定义__deepcopy__时我会如何忽略它? 此外,SQLA是否有任何属性注入映射对象?


(我在之前的一个问题中问过这个问题(在我选择主要问题的答案后几天作为编辑),但我想我错过了那里的火车。为此道歉。)

<小时/> Edit - Fixed code thanks to zifot's answer

我从Python文档中得到的唯一一点就是你需要定义带有memo的深度复制作为额外的参数。经过几十年的挖掘后,我尝试了这个:

def __deepcopy__(self, memo):
    dpcpy = self.__class__()
    memo[id(self)] = dpcpy
    for attr in dir(self):
        if not attr.startswith('_'):
            value = getattr(self, attr)
            setattr(dpcpy, attr, copy.deepcopy(value, memo))
    return dpcpy

然后我创建了User的实例:

snake = User(913, 'Snake,S.')  

之后,我尝试了deepcopy操作:

snake_dc = copy.deepcopy(snake)

...而snake_dc仍然包含SQLA属性......

我愿意提供帮助,建议等等。

4 个答案:

答案 0 :(得分:1)

mavnn is right。例如,尝试将用户的init更改为:

def __init__(self, user_id = None, name = None):
        self.user_id = user_id
        self.name = name

至于复制映射的实例,我建议阅读this thread

答案 1 :(得分:1)

当(深度)复制时,您不应该拨打__init__而是拨打__new__

一个例子:

def __copy__(self):
    cls = self.__class__
    newobject = cls.__new__(cls)
    newobject.__dict__.update(self.__dict__)
    return newobject

答案 2 :(得分:0)

我不是深度复制方面的专家,但从错误看起来你需要一个无参数构造函数来调用self.__class__()而不带参数。

答案 3 :(得分:0)

要排除sqlalchemy列和映射属性,您可以执行以下操作:

for attr in dir(self):
    if not self._sa_class_manager.mapper.has_property(key):
        ...