Pregunta

Estoy cambiando algunas clases mías de un uso extenso de getters y setters a un uso más pitónico de propiedades.

Pero ahora estoy atascado porque algunos de mis captadores o establecedores 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 las propiedades? ¿Cómo llamar al getter o setter de la propiedad en la clase padre?

Por supuesto, solo llamar 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
¿Fue útil?

Solución

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

class FooBar(Foo):

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

Aunque esto es lo más obvio, creo que lo creo: no funciona porque la barra es una propiedad, no es invocable.

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)

Otros consejos

Super debería hacer el truco:

return super().bar

En Python 2.x necesita usar la sintaxis más detallada:

return super(FooBar, self).bar

Existe una alternativa usando 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 padre A:

Como otros ya han respondido, es:

super(B, self).prop

O en Python 3:

super().prop

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

En B, accediendo al configurador de propiedades de la clase padre 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 usar super tiene la ventaja de ser independiente de las clases base de B . Si B heredara de una clase C que también extendiera la propiedad, no tendría que actualizar el código de B .

Código completo de B que extiende 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.

prueba

@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 súper función disponible.

Siempre puedes cambiar tu sintaxis 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()

(es decir, a menos que me falte algo de su explicación)

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top