2013-08-08 12 views
5

Ho un descrittore su una classe e il suo metodo __set__ non viene chiamato. Ho cercato a lungo e duro su questo per alcune ore e non ho una risposta per questo. Ma quello che ho notato di seguito è che quando assegno 12 a MyTest.X, cancella il descrittore di proprietà per X, e lo sostituisce con il valore di 12. Quindi viene richiamata l'istruzione print per la funzione Get. Quello è buono.Perché il descrittore Python __set__ non viene chiamato

Tuttavia, l'istruzione di stampa per la funzione __set__ NON viene richiamata. Mi sto perdendo qualcosa?

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

Sei sicuro di voler utilizzare gli attributi di classe anziché creare un'istanza? – user2357112

+0

Nel mio caso, che è molto complicato, questo è il wrapping di metodi statici, che alla fine vengono passati ai metodi statici di C++. –

+0

Almeno SWIG ha avuto alcuni problemi con i protocolli dei descrittori, quindi la soluzione potrebbe trovarsi anche nel tuo involucro C++, se fai cose più complesse di quelle mostrate qui. – schlenk

risposta

5

Le altre due risposte alludono all'uso di metaclassi per realizzare ciò che si vuole fare. Per contribuire ad imparare su di loro, ecco un esempio di applicazione di uno al codice nella tua domanda che lo rende fare quello che vuoi:

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

classi sono casi di loro metaclasse che è normalmente digitano type. Comunque puoi usarlo come una classe base e derivare la tua meta-sottoclasse specializzata - che in questo caso è quella che ha attributi di classe che sono descrittori di dati (cioè proprietà). Si noti che l'argomento self in un metodo meta o meta-sottoclasse è un'istanza metaclass, che è una classe. Nel codice sopra, è denominato MyTest.

+0

Grazie mille per aver mostrato un esempio di come funziona. –

3

L'__set__ unica viene chiamato quando si assegnare al X di un'istanza

Se si desidera che questo a lavorare per un attibute classe, si dovrà impostare il descrittore sulla metaclasse di MyTest

+0

Esiste comunque la possibilità di farlo fare ciò che voglio? –

+0

@CJohnson, certo, basta creare un metaclasse che lo faccia. –

+0

metaclass? Scusa, sono nuovo di Python. –

4

I descrittori funzionano su istanze di classi, non sulle classi stesse. Se avessi un'istanza di MyTest, X funzionerebbe come previsto, ma accedervi come un attributo di classe imposta effettivamente l'attributo dell'oggetto stesso. Potresti provare a definire un metaclasse personalizzato per aggiungere il descrittore a, quindi creare MyTest con tale metaclasse.

+0

Ok, ora guarda una meta classe –

Problemi correlati