自定义__getattr__和__setattr__的Python深度复制

时间:2016-11-14 06:37:54

标签: python python-2.7 copy getattr

我已经实现了一个类,它可以区分一组固定的实例属性(让他们称之为元属性)和一组任意的其他实例属性。

它有自定义__getattr____setattr__

class MyClass(object):

    def __init__(self, meta1, meta2, **other_attr):
        super(MyClass, self).__setattr__('meta1', meta1)
        super(MyClass, self).__setattr__('meta2', meta2)
        super(MyClass, self).__setattr__('params', {})

        self.params = {key: other_attr[key] for key in other_attr}


    # this is called when default lookup finds nothing
    def __getattr__(self, key):
        print('__getattr__({})'.format(key))
        try:
            return self.params[key]
        except KeyError:
            raise AttributeError(key)


    # this is called always
    def __setattr__(self, key, value):
        print('__setattr__({}, {})'.format(key, value))
        if key in self.__dict__:
            super(MyClass, self).__setattr__(key, value)
        else:
            self.params[key] = value

这很好用,所有元属性都直接进入实例的__dict__,而所有其他属性都进入params字典:

obj1 = MyClass(meta1 = 'foo', meta2 = 'bar', x=1, y=2, z=3)
obj1.w = 4
print(obj1.__dict__)

输出:

__setattr__(params, {'y': 2, 'x': 1, 'z': 3})
__setattr__(w, 4)
{'meta1': 'foo', 'meta2': 'bar', 'params': {'y': 2, 'x': 1, 'z': 3, 'w': 4}}

除非我尝试deepcopy我的对象,否则它会做一些奇怪的事情:

import copy
obj1 = MyClass(meta1='foo', meta2='bar', x=1, y=2, z=3)
obj2 = copy.deepcopy(obj1)

输出:

__setattr__(params, {'y': 2, 'x': 1, 'z': 3})
__getattr__(__deepcopy__)
__getattr__(__getnewargs__)
__getattr__(__getstate__)
__getattr__(__setstate__)
__getattr__(params)
__getattr__(params)
__getattr__(params)
__getattr__(params)
__getattr__(params)
__getattr__(params)
__getattr__(params)
__getattr__(params)
...
and then it calls __getattr__ about a hundred more times

最后 创建了一个副本,但为什么要拨打__getattr__进行这么多的调用?

1 个答案:

答案 0 :(得分:4)

这会导致递归查询(请记住obj2未通过__init__进行初始化)

return self.params[key]

你应该这样做

return super().__getattribute__('params')[key]