¿Cómo llamar a una propiedad de la clase base si esta propiedad se sobrescribe en la clase derivada?

Estoy cambiando algunas de mis clases de un uso extensivo de captadores y definidores a un uso más pirónico de las propiedades.

Pero ahora estoy atascado porque algunos de mis captadores o definidores anteriores llamarían al método correspondiente de la clase base y luego realizarían otra cosa. Pero, ¿cómo se puede lograr esto con propiedades? ¿Cómo llamar al captador o establecedor de propiedades en la clase padre?

Por supuesto, solo llamando al atributo en sí mismo da una recursión infinita.

class Foo(object): @property def bar(self): return 5 @bar.setter def bar(self, a): print a class FooBar(Foo): @property def bar(self): # return the same value # as in the base class return self.bar # --> recursion! @bar.setter def bar(self, c): # perform the same action # as in the base class self.bar = c # --> recursion! # then do something else print 'something else' fb = FooBar() fb.bar = 7 

Podría pensar que podría llamar a la función de clase base a la que llama la propiedad:

 class FooBar(Foo): @property def bar(self): # return the same value # as in the base class return Foo.bar(self) 

Aunque creo que esto es lo más obvio , no funciona porque el bar es una propiedad, no un reclamo.

Pero una propiedad es solo un objeto, con un método getter para encontrar el atributo correspondiente:

 class FooBar(Foo): @property def bar(self): # return the same value # as in the base class return Foo.bar.fget(self) 

Super debería hacer el truco:

 return super().bar 

En Python 2.x necesitas usar la syntax más detallada:

 return super(FooBar, self).bar 

Existe una alternativa que utiliza super que no requiere hacer referencia explícita al nombre de la clase base.

Clase base A:

 class A(object): def __init__(self): self._prop = None @property def prop(self): return self._prop @prop.setter def prop(self, value): self._prop = value class B(A): # we want to extend prop here pass 

En B, accediendo al captador de propiedades de la clase principal A:

Como otros ya han respondido, es:

 super(B, self).prop 

O en Python 3:

 super().prop 

Esto devuelve el valor devuelto por el getter de la propiedad, no el getter en sí mismo, pero es suficiente para extender el getter.

En B, accediendo al establecedor de propiedades de la clase principal A:

La mejor recomendación que he visto hasta ahora es la siguiente:

 A.prop.fset(self, value) 

Creo que este es mejor:

 super(B, self.__class__).prop.fset(self, value) 

En este ejemplo, ambas opciones son equivalentes, pero el uso de super tiene la ventaja de ser independiente de las clases base de B Si B heredara de una clase C también extendiera la propiedad, no tendría que actualizar el código de B

Código completo de B extendiendo la propiedad de A:

 class B(A): @property def prop(self): value = super(B, self).prop # do something with / modify value here return value @prop.setter def prop(self, value): # do something with / modify value here super(B, self.__class__).prop.fset(self, value) 

Una advertencia:

A menos que su propiedad no tenga un setter, debe definir tanto el setter como el getter en B incluso si solo cambia el comportamiento de uno de ellos.

tratar

 @property def bar: return super(FooBar, self).bar 

Aunque no estoy seguro de si Python admite llamar a la propiedad de clase base. Una propiedad es en realidad un objeto invocable que se configura con la función especificada y luego reemplaza ese nombre en la clase. Esto podría significar fácilmente que no hay una función super disponible.

Sin embargo, siempre puede cambiar su syntax para usar la función property ():

 class Foo(object): def _getbar(self): return 5 def _setbar(self, a): print a bar = property(_getbar, _setbar) class FooBar(Foo): def _getbar(self): # return the same value # as in the base class return super(FooBar, self)._getbar() def bar(self, c): super(FooBar, self)._setbar(c) print "Something else" bar = property(_getbar, _setbar) fb = FooBar() fb.bar = 7 
  class Base(object): def method(self): print "Base method was called" class Derived(Base): def method(self): super(Derived,self).method() print "Derived method was called" d = Derived() d.method() 

(Eso es a menos que me esté perdiendo algo de tu explicación)