2013-08-08 4 views
5

Ich habe einen Deskriptor für eine Klasse, und seine __set__-Methode wird nicht aufgerufen. Ich habe lange eingehend nach diesem Thema gesucht und habe dafür keine Antwort. Aber was ich unten bemerkte ist, dass wenn ich MyTest.X 12 zuweise, löscht er den Eigenschaftsdeskriptor für X und ersetzt ihn durch den Wert 12. Also wird die print-Anweisung für die Get-Funktion aufgerufen. Das ist gut.Warum wird der Python-Deskriptor __set__ nicht aufgerufen

Aber die print-Anweisung für die __set__ Funktion wird überhaupt nicht aufgerufen. Fehle ich etwas?

class _static_property(object): 
    ''' Descriptor class used for declaring computed properties that don't require a class instance. ''' 
    def __init__(self, getter, setter): 
     self.getter = getter 
     self.setter = setter 

    def __get__(self, instance, owner): 
     print "In the Get function" 
     return self.getter.__get__(owner)() 

    def __set__(self, instance, value): 
     print "In setter function" 
     self.setter.__get__()(value) 

class MyTest(object): 
    _x = 42 

    @staticmethod 
    def getX(): 
     return MyTest._x 

    @staticmethod 
    def setX(v): 
     MyTest._x = v 

    X = _static_property(getX, setX) 


print MyTest.__dict__ 
print MyTest.X 
MyTest.X = 12 
print MyTest.X 
print MyTest.__dict__ 
+0

Möchten Sie wirklich Klassenattribute verwenden, statt eine Instanz zu instanziieren? – user2357112

+0

In meinem Fall, der sehr kompliziert ist, ist dies Wrapping statische Methoden, die letztlich an C++ statische Methoden weitergegeben wird. –

+0

Zumindest hatte SWIG einige Probleme mit den Deskriptor-Protokollen, daher könnte die Lösung auch in Ihrer C++ - Wrapper-Ebene liegen, wenn Sie komplexere Dinge als hier gezeigt haben. – schlenk

Antwort

5

Die anderen beiden Antworten beziehen sich auf die Verwendung von Metaklassen, um das zu erreichen, was Sie tun möchten. Um über sie zu erfahren, hier ist ein Beispiel für eine auf den Code in Ihrer Frage Anwendung, die es macht, was Sie wollen:

class _static_property(object): 
    """Descriptor class used for declaring computed properties that 
     don't require a class instance. 
    """ 
    def __init__(self, getter, setter): 
     self.getter = getter 
     self.setter = setter 

    def __get__(self, obj, objtype=None): 
     print("In the getter function") 
     return self.getter(obj) 

    def __set__(self, obj, value): 
     print("In setter function") 
     self.setter(obj, value) 

class _MyMetaClass(type): 
    def getX(self): 
     return self._x 

    def setX(self, v): 
     self._x = v 

    X = _static_property(getX, setX) 

class MyTest(object): 
    __metaclass__ = _MyMetaClass # Python 2 syntax 
    _x = 42 

#class MyTest(object, metaclass=_MyMetaClass): # Python 3 (only) syntax 
# _x = 42 

print(MyTest.__dict__) 
print(MyTest.X) 
MyTest.X = 12 
print(MyTest.X) 
print(MyTest.__dict__) 

Klassen sind Instanzen ihrer Metaklasse, die normalerweise type wird geben. Sie können dies jedoch als Basisklasse verwenden und Ihre eigene spezialisierte Meta-Unterklasse ableiten - das sind in diesem Fall Klassenattribute, die Datendeskriptoren sind (auch bekannt als Eigenschaften). Beachten Sie, dass das Argument self in einer Meta- oder Metasubklassenmethode eine Metaklasseninstanz ist, bei der es sich um eine Klasse handelt. Im obigen Code heißt es MyTest.

+0

Vielen Dank für ein Beispiel, wie das funktioniert. –

3

Die __set__ nur aufgerufen wird, wenn Sie X einer Instanz

zuweisen Wenn Sie dies für eine Klasse attibute arbeiten möchten, müssen Sie den Deskriptor auf der Metaklasse von MyTest einrichten müssen

+0

Gibt es trotzdem etwas zu machen was ich will? –

+0

@CJohnson, sicher, mach einfach eine Metaklasse, die das tut. –

+0

Metaklasse? Tut mir leid, ich bin neu bei Python. –

4

Deskriptoren arbeiten an Instanzen von Klassen, nicht an Klassen selbst. Wenn Sie eine Instanz von MyTest hätten, würde X wie erwartet funktionieren, aber der Zugriff darauf als Klassenattribut setzt tatsächlich das Attribut des Klassenobjekts selbst. Sie könnten versuchen, eine benutzerdefinierte Metaklasse zu definieren, der den Deskriptor hinzufügt, und dann MyTest mit dieser Metaklasse zu erstellen.

+0

Ok, eine Meta-Klasse jetzt nachschlagen –

Verwandte Themen