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