复制自定义对象时出现深层复制失败

Anu*_*rma 8 python class class-method python-2.7

我有一个类将字典转换为这样的对象

class Dict2obj(dict):
    __getattr__= dict.__getitem__

    def __init__(self, d):
        self.update(**dict((k, self.parse(v))
                           for k, v in d.iteritems()))

   @classmethod
   def parse(cls, v):
    if isinstance(v, dict):
        return cls(v)
    elif isinstance(v, list):
        return [cls.parse(i) for i in v]
    else:
        return v
Run Code Online (Sandbox Code Playgroud)

当我尝试制作对象的深层副本时,我收到了此错误

import copy
my_object  = Dict2obj(json_data)
copy_object = copy.deepcopy(my_object)

File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/copy.py", line 172, in deepcopy
copier = getattr(x, "__deepcopy__", None)
KeyError: '__deepcopy__'
Run Code Online (Sandbox Code Playgroud)

但是我在类I中重写getattr函数Dict2obj能够进行深层复制操作.见下面的例子

class Dict2obj(dict):

    __getattr__= dict.__getitem__

    def __init__(self, d):
        self.update(**dict((k, self.parse(v))
                           for k, v in d.iteritems()))

    def __getattr__(self, key):
        if key in self:
            return self[key]
        raise AttributeError

    @classmethod
    def parse(cls, v):
        if isinstance(v, dict):
            return cls(v)
        elif isinstance(v, list):
            return [cls.parse(i) for i in v]
        else:
            return v
Run Code Online (Sandbox Code Playgroud)

为什么我需要覆盖getattr方法才能对此类的对象返回进行深度复制

Ana*_*mar 9

第一堂课会出现问题,因为copy.deepcopy试图打电话getattr(x, "__deepcopy__", None).第三个参数的意义在于,如果对象不存在该属性,则返回第三个参数.

这在以下文档中给出getattr() -

getattr(object, name[, default])

返回object的named属性的值.name必须是一个字符串.如果字符串是对象属性之一的名称,则结果是该属性的值.例如,getattr(x,'foobar')等同于x.foobar.如果named属性不存在,则返回default(如果提供),否则引发AttributeError.

这样做,如果为函数调用提供了底层__getattr__引发AttributeErrordefault参数,则getattr()函数AttributeError捕获getattr()它并返回默认参数,否则它会AttributeError冒泡.示例 -

>>> class C:
...     def __getattr__(self,k):
...             raise AttributeError('asd')
...
>>>
>>> c = C()
>>> getattr(c,'a')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in __getattr__
AttributeError: asd
>>> print(getattr(c,'a',None))
None
Run Code Online (Sandbox Code Playgroud)

但是,在你的情况,因为你直接分配dict.__getitem____getattr__,如果名称未在词典中找到,它提出了一个KeyError,而不是一个AttributeError,因此它不会被处理getattr(),你的copy.deepcopy()失败.

你应该处理KeyError你的getattr,然后提高AttributeError.示例 -

class Dict2obj(dict):

    def __init__(self, d):
        self.update(**dict((k, self.parse(v))
                           for k, v in d.iteritems()))

    def __getattr__(self, name):
        try:
            return self[name]
        except KeyError:
            raise AttributeError(name)
    ...
Run Code Online (Sandbox Code Playgroud)