it-swarm.com.de

So verwenden Sie __setattr__ richtig und vermeiden eine unendliche Rekursion

Ich möchte eine Klasse definieren, die die Methoden read und write enthält, die wie folgt aufgerufen werden können:

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

Um keine Interlaced-Klassen zu verwenden, bestand meine Idee darin, die Methoden __getattr__ Und __setattr__ Zu überschreiben und zu überprüfen, ob der angegebene Name device ist, um die Rückgabe an self. Aber ich bin auf ein Problem gestoßen, bei dem es zu unendlichen Rekursionen gekommen ist. Der Beispielcode lautet wie folgt:

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)

Da in __init__ Der Code versucht hat, ein neues Attribut x zu erstellen, ruft er __setattr__ Auf, das wiederum __setattr__ Und so weiter aufruft. Wie muss ich diesen Code ändern, damit in diesem Fall ein neues Attribut x von self mit dem Wert 1 Erstellt wird?

Oder gibt es eine bessere Möglichkeit, mit Aufrufen wie instance.device.read Umzugehen, die auf instance.read 'Abgebildet' werden?

Da es immer Fragen zum Warum gibt: Ich muss Abstraktionen von xmlrpc Aufrufen erstellen, für die sehr einfache Methoden wie myxmlrpc.instance,device.read Und ähnliches erstellt werden können. Ich muss dies verspotten, um solche Multi-Dot-Methoden-Aufrufe nachzuahmen.

47
Alex

Sie müssen die übergeordnete Klasse __setattr__ Aufrufen:

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)

In Bezug auf die Best-Practice, da Sie dies über xml-rpc Verwenden möchten, denke ich, dass dies in der _dispatch -Methode wahrscheinlich besser gemacht wird.

Ein schneller und schmutziger Weg ist, einfach Folgendes zu tun:

class My(object):
    def __init__(self):
        self.device = self
49
Bakuriu

Oder Sie können self.__dict__ In __setattr__() ändern:

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

Sie können auch Objekt verwenden.

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)
4
Danny Harpigny

oder Sie können einfach @property verwenden:

class MyTest(object):

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

    @property
    def device(self):
        return self
0
Aviad Rozenhek