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