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

时间:2015-10-28 09:52:35

标签: python python-2.7 class class-method

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

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

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

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__'

但是我在Dict2obj类中覆盖了 getattr 函数,我能够进行深层复制操作。见下面的例子

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

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

1 个答案:

答案 0 :(得分:8)

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

这在the documentation for getattr() -

中给出
  

<强> getattr(object, name[, default])

     

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

如果为__getattr__函数调用提供基础AttributeError引发defaultgetattr()参数,则AttributeErrorgetattr()捕获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 冒泡。示例 -

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) ... 。示例 -

Sub asdf()


    With Range("B1:B2").Validation
        .Delete
        .Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, Operator:= _
        xlBetween, Formula1:="=INDIRECT(INDIRECT(""RC[-1]"",0))"
        .IgnoreBlank = True
        .InCellDropdown = True
        .InputTitle = ""
        .ErrorTitle = ""
        .InputMessage = ""
        .ErrorMessage = ""
        .ShowInput = True
        .ShowError = True
    End With

End Sub