2013-06-10 10 views
30

Chcę, aby zdefiniować klasę zawierającą read i write methode, które można nazwać w następujący sposób:Jak korzystać __setattr__ poprawnie, unikając nieskończoną rekurencję

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

Aby nie używać klas przeplotem, mój pomysł był aby zastąpić __getattr__ i __setattr__ metody i sprawdzić, czy podana nazwa to device, aby przekierować powrót do self. Ale napotkałem problem z nieskończoną rekurencją. Przykładowy kod jest następujący:

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) 

jak w __init__ kod próbował stworzyć nowy atrybut x, wywołuje __setattr__, który ponownie wzywa __setattr__ i tak dalej. Jak muszę zmienić ten kod, aby w tym przypadku utworzyć nowy atrybut x z self, zawierający wartość 1?

Czy istnieje lepszy sposób na obsłużenie połączeń, takich jak instance.device.read, aby zostać "zamapowanymi" na instance.read?

Ponieważ zawsze są pytania dotyczące tego, dlaczego: Potrzebuję tworzyć abstrakcje połączeń xmlrpc, dla których można stworzyć bardzo proste metody, takie jak myxmlrpc.instance,device.read i podobne. Muszę "kpić" z tego, aby naśladować takie połączenia z wieloma kropkami.

Odpowiedz

34

Należy zadzwonić klasy nadrzędnej __setattr__ metody:

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) 

odniesieniu do najlepszych praktyk, ponieważ masz zamiar to wykorzystać poprzez xml-rpc myślę, to chyba lepiej zrobić wewnątrz metody _dispatch.

Szybki i brudny sposobem jest po prostu zrobić:

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

Podoba mi się szybki i nieuporządkowany sposób: wystarczy jedna linia, aby uzyskać pożądane zachowanie! Dzięki – Alex

11

Albo można modyfikować self.__dict__ od wewnątrz __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

Można również użyć obiekt.

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) 
Powiązane problemy