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


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

но теперь я застрял, потому что некоторые из моих предыдущих геттеров или сеттеров будут вызывать соответствующий метод базового класса, а затем выполнять что-то еще. Но как это можно сделать со свойствами? Как вызвать свойство 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
5 69

5 ответов:

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

class FooBar(Foo):

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

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

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

class FooBar(Foo):

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

супер следует сделать трюк:

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, доступ к свойству getter родительского класса 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 ' s код.

полный код расширения 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()

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