2013-06-10 17 views
30

voglio definire una classe contenente read e write Methode, che può essere chiamato come segue:Come utilizzare __setattr__ correttamente, evitando infinita ricorsione

instance.read 
instance.write 
instance.device.read 
instance.device.write 

Per non utilizzare le classi interlacciati, la mia idea era quella di sovrascrivere il __getattr__ e __setattr__ metodi e per verificare, se il nome dato è device per reindirizzare il ritorno a self. Ma ho riscontrato un problema con ricorsioni infinite. Il codice di esempio è il seguente:

class MyTest(object): 
    def __init__(self, x): 
     self.x = x 

    def __setattr__(self, name, value): 
     if name=="device": 
      print "device test" 
     else: 
      setattr(self, name, value) 

test = MyTest(1) 

Come nel __init__ codice cercato di creare un nuovo attributo x, chiama __setattr__, che chiama nuovamente __setattr__ e così via. Come devo cambiare questo codice, in questo caso viene creato un nuovo attributo x di self, contenente il valore 1?

Oppure esiste un modo migliore per gestire chiamate come instance.device.read da "mappare" a instance.read?

Come sempre ci sono domande sul perché: ho bisogno di creare astrazioni di chiamate xmlrpc, per le quali è possibile creare metodi molto semplici come myxmlrpc.instance,device.read e simili. Ho bisogno di "deridere" questo per imitare tali chiamate con metodo multi-punto.

risposta

34

è necessario chiamare la classe genitore __setattr__ metodo:

class MyTest(object): 

    def __init__(self, x): 
     self.x = x 

    def __setattr__(self, name, value): 
     if name=="device": 
      print "device test" 
     else: 
      super(MyTest, self).__setattr__(name, value) 
      # in python3+ you can omit the arguments to super: 
      #super().__setattr__(name, value) 

Per quanto riguarda la best-practice, dal momento che si prevede di utilizzare questa via xml-rpc Penso che questo è probabilmente meglio fare all'interno del metodo _dispatch.

Un modo rapido e sporco è quello di fare semplicemente:

class My(object): 
    def __init__(self): 
     self.device = self 
+0

Mi piace il modo rapido e sporco: solo una riga per ottenere il comportamento desiderato! Grazie – Alex

11

Oppure è possibile modificare self.__dict__ dall'interno __setattr__():

class SomeClass(object): 

    def __setattr__(self, name, value): 
     print(name, value) 
     self.__dict__[name] = value 

    def __init__(self, attr1, attr2): 
     self.attr1 = attr1 
     self.attr2 = attr2 


sc = SomeClass(attr1=1, attr2=2) 

sc.attr1 = 3 
1

È inoltre possibile utilizzare oggetto.

class TestClass: 
    def __init__(self): 
      self.data = 'data' 
    def __setattr__(self, name, value): 
      print("Attempt to edit the attribute %s" %(name)) 
      object.__setattr__(self, name, value) 
Problemi correlati