2015-10-28 9 views
8

Ich habe eine Klasse, die wie diesetiefe Kopie Fehler, wenn benutzerdefiniertes Kopieren Objekt

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 

einen Wörterbuch in ein Objekt konvertieren Wenn ich versuche, eine tiefe Kopie des Objekts zu machen ich diesen Fehler bekam

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

Aber ich Override Getattr Funktion in Dict2obj Klasse konnte ich tiefe Kopieroperation tun. Siehe Beispiel unten

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 

Warum muss ich getattr Methode, um außer Kraft zu setzen brauchen eine deep von Objekten zurückgeben von dieser Klasse

Antwort

6

Das Problem tritt für die erste Klasse zu tun, weil copy.deepcopy versucht getattr(x, "__deepcopy__", None) zu nennen . Die Bedeutung des dritten Arguments besteht darin, dass das dritte Argument zurückgegeben wird, wenn das Attribut für das Objekt nicht existiert.

Dies ist in the documentation for getattr() gegeben -

getattr(object, name[, default])

Rückkehr der Wert des benannten Attributs des Objekts. name muss eine Zeichenfolge sein. Wenn die Zeichenfolge der Name eines der Attribute des Objekts ist, ist das Ergebnis der Wert dieses Attributs. Zum Beispiel entspricht getattr (x, 'foobar') x.foobar. Wenn das benannte Attribut nicht vorhanden ist, wird der Standardwert zurückgegeben, sofern dies angegeben ist, andernfalls wird AttributeError ausgelöst.

Dies funktioniert wie, wenn die zugrunde liegende __getattr__AttributeError hebt und das default Argument wurde für die getattr() Funktion zur Verfügung gestellt rufen die AttributeError durch die getattr() Funktion gefangen wird, und es gibt das Standardargument, sonst lässt es die AttributeError sprudeln. Beispiel -

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

Aber in Ihrem Fall, da Sie direkt dict.__getitem__-__getattr__ zuweisen, wenn der Name nicht im Wörterbuch gefunden wird, es stellt sich ein KeyError, kein AttributeError und daher ist es nicht von getattr() behandelt bekommen und Ihre copy.deepcopy() schlägt fehl.

Sie sollten die KeyError in Ihrem getattr behandeln und dann AttributeError stattdessen erhöhen. Beispiel -

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) 
    ... 
Verwandte Themen