2015-10-28 61 views
8

當我有轉換的字典對象這樣深複製失敗複製自定義對象

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

但我重寫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 

爲什麼我需要重寫GETATTR方法,爲了做到對象的deepcopy的這個類

回答

6

出現你的第一類問題返回,因爲copy.deepcopy試圖調用getattr(x, "__deepcopy__", None) 。第三個參數的意義在於,如果對象不存在該屬性,則它返回第三個參數。

getattr(object, name[, default])

返回對象的指定屬性的值 -

這在the documentation for getattr()給出。名稱必須是字符串。如果字符串是對象屬性之一的名稱,則結果是該屬性的值。例如,getattr(x,'foobar')等同於x.foobar。 如果指定的屬性不存在,則返回默認值(如果提供),否則引發AttributeError

這個工作過程,如果標的__getattr__提高AttributeError並提供default參數爲getattr()函數調用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()失敗。

您應該在getattr中處理KeyError,然後改爲提升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) 
    ...