2015-10-28 11 views
8

Ho una classe che convertono un dizionario ad un oggetto come questoprofondo fallimento copia quando si copia oggetto personalizzato

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 

Quando provo a fare una copia completa dell'oggetto ho ottenuto questo errore

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

Ma di I override getattr funzione nella classe Dict2obj Sono stato in grado di eseguire un'operazione di copia profonda. Vedere l'esempio di seguito

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 

Perché è necessario eseguire l'override getattr metodo al fine di fare un deepcopy di oggetti tornare da questa classe di

risposta

6

Il problema si verifica per la prima classe, perché copy.deepcopy tenta di chiamare getattr(x, "__deepcopy__", None) . Il significato del terzo argomento è che, se l'attributo non esiste per l'oggetto, restituisce il terzo argomento.

Questo è dato in the documentation for getattr() -

getattr(object, name[, default])

ritorno il valore dell'attributo di nome di oggetto. il nome deve essere una stringa. Se la stringa è il nome di uno degli attributi dell'oggetto, il risultato è il valore di tale attributo. Ad esempio, getattr (x, 'foobar') è equivalente a x.foobar. Se l'attributo named non esiste, viene restituito il valore predefinito se fornito, altrimenti viene sollevato l'Errore attributo.

Questo funziona come, se il sottostante __getattr__ solleva AttributeError e l'argomento default è stato fornito per la funzione getattr() chiamano il AttributeError 'colto dalla funzione getattr() e restituisce l'argomento di default, altrimenti lascia il AttributeError bolla. Esempio -

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

ma nel tuo caso, dal momento che si assegna direttamente dict.__getitem__-__getattr__, se il nome non si trova nel dizionario, si solleva un KeyError, non un AttributeError e, quindi, non viene gestita da getattr() e il tuo copy.deepcopy() fallisce.

È necessario gestire KeyError nel proprio getattr e quindi aumentare AttributeError. Esempio -

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) 
    ... 
Problemi correlati