【发布时间】:2020-11-15 04:58:08
【问题描述】:
考虑以下代码:
class A():
def __init__(self, thing):
self.thing = thing
def do_something(self):
if self.thing > 0:
print('thing is positive')
else:
print('thing is not positive')
def some_function(a):
if a.thing > 0:
print('this thing is positive')
else:
print('this thing is not positive')
class B(A):
@property
def thing(self):
return 0
@thing.setter
def thing(self, val):
pass
# Purposely don't want to override A.do_something
a = A(5)
print(a.thing) # 5
a.do_something() # thing is positive
some_function(a) # this thing is positive
isinstance(a, A) # True
b = B(5)
print(b.thing) # 0
b.do_something() # thing is not positive (!!! - not what we want - see below)
some_function(b) # this thing is not positive
isinstance(b, A) # True
假设do_something 是一个我们不想重写的复杂函数。这可能是因为它位于外部包中,我们希望能够继续使用包含A 的此包的最新版本,而不必每次都更新B。现在假设一个外部函数通过直接引用它来访问a.thing。我们希望B 扩展A 以便这个外部函数总是看到b.thing == 0。但是,我们希望在不修改内部方法行为的情况下做到这一点。在上面的例子中,我们想要修改some_function 的行为,但是我们这样做的代价是同时改变了内部方法b.do_something 的行为。
解决这个问题的明显方法是让外部函数some_function 使用get_thing() 方法。但是如果这些外部函数已经写在另一个包中,修改这些是不可能的。
另一种方法是让B 在调用父类的方法之前更新self.thing 的值,
class B(A):
def __init__(self, thing):
self.thing = 0
self._thing = thing
def do_something(self):
self.thing = self._thing
rval = super().do_something()
self.thing = 0
return rval
然而这看起来很笨拙,如果A 的开发者添加了新方法,那么B 会在这些方法没有更新的情况下改变这些方法的行为。
关于如何扩展这样的类是否有最佳实践,如果由外部函数调用,它允许使用覆盖__getattribute__,但不改变任何内部行为?
【问题讨论】:
标签: python oop inheritance properties getter-setter