如何在派生类中调用被重写的基类属性?
我正在把我的一些类从大量使用获取器和设置器,改成更符合Python风格的属性使用。
但是现在我遇到了困难,因为我之前的一些获取器或设置器会调用基类中对应的方法,然后再执行其他操作。但是用属性怎么实现这个呢?怎么才能在父类中调用属性的获取器或设置器呢?
当然,直接调用属性本身会导致无限递归。
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
7 个回答
31
有一种使用 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
中定义设置器和获取器。
71
115
你可能会认为可以直接调用由属性调用的基类函数:
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)