2009-06-29 16 views
5

Questa domanda è simile a this other one, con la differenza che il membro dati nella classe base è non avvolto dal protocollo descrittore.Come chiamare un membro dati della classe base se viene sovrascritto come una proprietà nella classe derivata?

In altre parole, come posso accedere a un membro della classe base se sto sovrascrivendo il suo nome con una proprietà nella classe derivata?

class Base(object): 
    def __init__(self): 
     self.foo = 5 

class Derived(Base): 
    def __init__(self): 
     Base.__init__(self) 

    @property 
    def foo(self): 
     return 1 + self.foo # doesn't work of course! 

    @foo.setter 
    def foo(self, f): 
     self._foo = f 

bar = Base() 
print bar.foo 

foobar = Derived() 
print foobar.foo 

prega di notare che ho anche bisogno di definire un setter perché altrimenti l'assegnazione di self.foo nella classe base non funziona.

Tutto sommato il protocollo descrittore non sembra di interagire bene con l'eredità ...

risposta

4

Definizione

def __init__(self): 
    self.foo = 5 

in Base rende foo un membro (attributi) del esempio, non della classe. La classe Base non è a conoscenza di foo, quindi non c'è modo di accedervi da qualcosa come una chiamata super().

Questo non è necessario, tuttavia. Quando si instanciate

foobar = Derived() 

e il metodo della classe base __init__() chiama

self.foo = 5 

ciò non comporterà la creazione/sovrascrittura dell'attributo, ma invece in Derived s' setter essere chiamato significato

self.foo.fset(5) 

e quindi self._foo = 5. Quindi se metti

return 1 + self._foo 

nel tuo getter, ottieni praticamente quello che vuoi. Se è necessario il valore che è self.foo impostato nel costruttore Base, basta guardare _foo, che è stato impostato correttamente dal @foo.setter.

+0

Tutte le risposte sono molto interessanti e mi upvoted la maggior parte di loro, ma questo era dritto al il punto, mi ha davvero fatto capire il problema a portata di mano. – UncleZeiv

0

una volta che hai proprietà con lo stesso nome 'foo' si sovrascrive il comportamento di accesso del nome 'foo' sembra unica via d'uscita che si imposta in modo esplicito 'pippo' in __dict__

btw: Io uso python 2.5 quindi dovuto cambiare un po 'il codice

class Base(object): 
    def __init__(self): 
     self.foo = 5 

class Derived(Base): 
    def __init__(self): 
     Base.__init__(self) 

    def g_foo(self): 
     return 1 + self.__dict__['foo'] # works now! 

    def s_foo(self, f): 
     self.__dict__['foo'] = f 
     self._foo = f 

    foo = property(g_foo, s_foo) 

bar = Base() 
print bar.foo 

foobar = Derived() 
print foobar.foo 
9

la vita è più semplice se si utilizza la delega al posto di eredità. Questo è Python. Non sei obbligato ad ereditare da Base.

class LooksLikeDerived(object): 
    def __init__(self): 
     self.base= Base() 

    @property 
    def foo(self): 
     return 1 + self.base.foo # always works 

    @foo.setter 
    def foo(self, f): 
     self.base.foo = f 

Ma che dire degli altri metodi di Base? Duplicare i nomi in LooksLikeDerived e semplicemente.

def someMethodOfBase(self, *args, **kw): 
    return self.base.someMethodOfBase(*args **kw) 

Sì, non si sente "SECCO". Tuttavia, previene un sacco di problemi quando "avvolge" alcune classi in nuove funzionalità come si sta tentando di fare.

+0

Sì, in effetti sto cercando altri modi "pitonici" per organizzare il mio codice, e per un po 'ho messo in discussione il mio approccio basato sull'eredità. La tua alternativa, tuttavia, non è convincente nel mio caso, poiché ho una catena di ereditarietà a più livelli, in cui ogni livello definisce nuove funzionalità. Dovendo ridefinire tutti i metodi ad ogni livello sarebbe decisamente irrealizzabile. Ma capisco il tuo punto. – UncleZeiv

+0

@UncleZeiv: questa non è una situazione di EITH-OR. Hai molti, molti modelli di design, tra cui strategia, composizione, delega ed ereditarietà. Concentrarsi sull'ereditarietà è una brutta cosa. –

1
class Foo(object): 
    def __new__(cls, *args, **kw): 
     return object.__new__(cls, *args, **kw) 

    def __init__(self): 
     self.foo = 5 

class Bar(Foo): 
    def __new__(cls, *args, **kw): 
     self = object.__new__(cls, *args, **kw) 
     self.__foo = Foo.__new__(Foo) 
     return self 

    def __init__(self): 
     Foo.__init__(self) 

    @property 
    def foo(self): 
     return 1 + self.__foo.foo 

    @foo.setter 
    def foo(self, foo): 
     self.__foo.foo = foo 

bar = Bar() 
bar.foo = 10 
print bar.foo 
0

Onestamente, la cosa da guardare qui è che stai cercando di distorcere il codice attorno a un progetto che è semplicemente scadente. I descrittori di proprietà gestiscono la richiesta di un attributo 'foo' e tu vuoi ignorarli completamente, il che è sbagliato. Stai già causando Base. init per assegnare foobar._foo = 5, quindi questo è esattamente dove deve essere guardato il getter.

Classe base (oggetto): def init (self): self.foo = 5

class Derived(Base): 
    def __init__(self): 
    Base.__init__(self) 

    @property 
    def foo(self): 
    return 1 + self._foo # DOES work of course! 

    @foo.setter 
    def foo(self, f): 
    self._foo = f 

bar = Base() 
print bar.foo 

foobar = Derived() 
print foobar.foo 
Problemi correlati