Как вызвать свойство базового класса, если это свойство перезаписывается в производном классе?

Я меняю несколько классов из широкого использования геттеров и сеттеров для более питонического использования свойств.

Но теперь я застрял, потому что некоторые из моих предыдущих геттеров или сеттеров вызывали соответствующий метод базового класса, а затем выполняли что-то еще. Но как это можно осуществить со свойствами? Как вызвать свойство getter или setter в родительском классе?

Конечно, просто вызов самого атрибута дает бесконечную рекурсию.

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

Ответ 1

Вы могли бы подумать, что можете вызвать функцию базового класса, которая вызывается свойством:

class FooBar(Foo):

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

Хотя это самое очевидное, что я думаю - он не работает, потому что bar является свойством, а не вызываемым.

Но свойство - это просто объект с методом getter, чтобы найти соответствующий атрибут:

class FooBar(Foo):

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

Ответ 2

Super должен сделать трюк:

return super().bar

В Python 2.x вам нужно использовать более подробный синтаксис:

return super(FooBar, self).bar

Ответ 3

Существует альтернатива, использующая super, которая не требует явно ссылаться на имя базового класса.

Базовый класс 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

В B доступ к получателю свойства родительского класса A:

Как уже ответили другие, это:

super(B, self).prop

Или в Python 3:

super().prop

Это возвращает значение, возвращаемое получателем свойства, а не сам геттер, но достаточно для расширения получателя.

В B доступ к устройству свойств родительского класса A:

Лучшая рекомендация, которую я видел до сих пор, заключается в следующем:

A.prop.fset(self, value)

Я считаю, что это лучше:

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

В этом примере обе опции эквивалентны, но использование супер имеет то преимущество, что оно не зависит от базовых классов B. Если B наследовалось от класса C, также расширяющего свойство, вам не нужно было бы обновлять код B.

Полный код B, расширяющий свойство 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
        return super(B, self.__class__).prop.fset(self, value)

Одно предупреждение:

Если ваше свойство не имеет сеттера, вы должны определить как установщик, так и получатель в B, даже если вы только измените поведение одного из них.

Ответ 4

попробовать

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

Хотя я не уверен, поддерживает ли python вызов свойства базового класса. Свойство - фактически вызываемый объект, который настроен с указанной функцией, а затем заменяет это имя в классе. Это может легко означать, что суперфункция недоступна.

Вы всегда можете переключить свой синтаксис, чтобы использовать функцию 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

Ответ 5

    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()

(то есть, если я не упустил что-то из вашего объяснения)