2015-08-09 16 views
8

ho una classe denominata Node che ha un importance setter e getter, qui di seguito:override un setter proprietà ereditata

class Node: 

    @property 
    def importance(self): 
     return self._importance 

    @importance.setter 
    def importance(self, new_importance): 
     if new_importance is not None: 
      new_importance = check_type_and_clean(new_importance, int) 
      assert new_importance >= 1 and new_importance <= 10 
     self._importance = new_importance 

Più tardi, ho una classe che eredita da TheoremNode. L'unica differenza tra uno Theorem e uno Node, per quanto riguarda importance, è che uno Theorem deve avere uno importance di almeno 3.

Come può un ereditare Teorema il importance setter, ma aggiungere il vincolo aggiuntivo che importance >= 3?

ho cercato di fare in questo modo:

class Theorem(Node): 

    @importance.setter 
    def importance(self, new_importance): 
     self.importance = new_importance # hoping this would use the super() setter 
     assert self.importance >= 3 
+2

Nota: si potrebbe risolvere il problema in modo completamente diverso avendo un attributo di classe 'MIN_IMPORTANCE' che è' 1' in 'Nodo' e' 3' in 'Teorema'. – jonrsharpe

+0

Possibile duplicato di [Sovrascrivere le proprietà in python] (http://stackoverflow.com/questions/7019643/overriding-properties-in-python) –

risposta

6

È possibile fare riferimento alla proprietà esistente direttamente attraverso la classe Node, e utilizzare il metodo della struttura setter per creare una nuova proprietà da esso:

class Theorem(Node): 
    @Node.importance.setter 
    def importance(self, new_importance): 
     # You can change the order of these two lines: 
     assert new_importance >= 3 
     Node.importance.fset(self, new_importance) 

Questo creerà una nuova proprietà nella classe Theorem che utilizza il metodo getter da Node.importance ma sostituisce il metodo setter con uno diverso. Ecco come funzionano le proprietà in generale: la chiamata di una proprietà setter restituisce una nuova proprietà con un setter personalizzato, che in genere sostituisce semplicemente la vecchia proprietà.

È possibile ottenere ulteriori informazioni su come funzionano le proprietà leggendo this answer (e anche la domanda).

+1

'TypeError: setter() richiede esattamente un argomento (2 dato)'. Intendevi 'fset'? – jonrsharpe

+0

@jonrsharpe Ups, prova ora: P –

+1

Sì, molto meglio e più ordinato del mio! – jonrsharpe

3

Un modo per farlo è mediante l'attuazione di una nuova proprietà sul Theorem utilizzando il Node getter, fornendo un nuovo metodo setter e chiamando il Node setter esplicitamente al suo interno:

class Theorem(Node): 

    def _set_importance(self, new): 
     Node.importance.fset(self, new) 
     assert self.importance >= 3 

    importance = property(Node.importance.fget, _set_importance) 

Per quanto ne sono a conoscenza , questo non può essere fatto con super.


Per this bug report, si potrebbe fare:

class Theorem(Node): 

    def _set_importance(self, new): 
     super(Theorem, Theorem).importance.fset(self, new) 
     assert self.importance >= 3 

    importance = property(Node.importance.fget, _set_importance) 

Tuttavia, questo è chiaramente un po 'scomodo; la patch per consentire super() invece sembra essere pianificata per Python 3.5 (dovuto in September 2015).

+0

Non passare 'self .__ class__' a' super() '. Si romperà totalmente quando sottoclassi da 'Theorem'. – Kevin

+0

@Kevin lo farà? Un test rapido indica che sta passando a 'Node.importance.fset' da un'istanza di sottoclasse di' Theorem'. – jonrsharpe

+0

ISTM che 'super (TheoremSubclass, TheoremSubclass) .importance' restituirà l'oggetto creato sull'ultima riga. Questo dovrebbe produrre una ricorsione infinita una volta chiamato 'fset()'. – Kevin

1

Ecco una soluzione completamente diversa al problema più ampio, con molto meno cazzeggio:

class Node: 

    MIN_IMPORTANCE = 1 
    MAX_IMPORTANCE = 10 

    @property 
    def importance(self): 
     return self._importance 

    @importance.setter 
    def importance(self, new_importance): 
     if new_importance is not None: 
      new_importance = check_type_and_clean(new_importance, int) 
      assert (new_importance >= self.MIN_IMPORTANCE and 
        new_importance <= self.MAX_IMPORTANCE) 
     self._importance = new_importance 


class Theorem(Node): 

    MIN_IMPORTANCE = 3 

    # and that's all it takes! 

A mio avviso, questo esprime:

The only difference between a Theorem and a Node , as far as importance is concerned, is that a Theorem must have an importance of at least 3 .

molto più chiaramente che l'override del fa il setter della proprietà.


noti che assert è generalmente utilizzato per il test e il debug, piuttosto che come parte del flusso generale del programma, e certamente non per le cose che ci si aspetta potrebbe succedere; vedere per es. Best practice for Python Assert.

Problemi correlati