¿Cómo llamar a una propiedad de la clase base si esta propiedad está siendo sobrescrita en la clase derivada?


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

Pero ahora estoy atascado porque algunos de mis getters o setters anteriores llamaban al método correspondiente de la clase base, y luego realizaban otra cosa. Pero, ¿cómo se puede lograr esto con propiedades? ¿Cómo llamar a la propiedad getter o setter en la clase padre?

Por supuesto, solo llamar al atributo en sí da 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
Author: spinkus, 2009-06-20

5 answers

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 esta es la cosa más obvia para probar creo - no funciona porque bar es una propiedad, no un callable.

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)
 80
Author: David Cournapeau,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-09-09 18:53:04

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
 40
Author: Pankrat,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-10-30 19:05:10

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 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í, pero es suficiente para extender el getter.

En B, acceder a la propiedad setter 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:{[13]]}

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 fuera a heredar de una clase C que también extiende 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)

Uno advertencia:

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

 16
Author: Maxime R.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-05-15 12:27:11

Intenta

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

Aunque no estoy seguro de si python soporta llamar a la propiedad clase base. Una propiedad es en realidad un objeto llamable 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
 4
Author: workmad3,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-20 12:16:06
    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 esté perdiendo algo de su explicación)

 -1
Author: shylent,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-20 11:51:44