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

StackOverflow https://stackoverflow.com/questions/1021464

Вопрос

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

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

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

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
Это было полезно?

Решение

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

class FooBar(Foo):

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

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

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

class FooBar(Foo):

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

Другие советы

Super должен помочь:

return super().bar

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

return super(FooBar, self).bar

Существует альтернатива с использованием 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)

В этом примере оба параметра эквивалентны, но преимущество super заключается в том, что они независимы от базовых классов 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
        super(B, self.__class__).prop.fset(self, value)

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

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

пытаться

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top