调用被覆盖的方法,超类调用被覆盖的方法
Posted
技术标签:
【中文标题】调用被覆盖的方法,超类调用被覆盖的方法【英文标题】:Calling an overridden method, superclass an calls overridden method 【发布时间】:2011-12-13 03:53:34 【问题描述】:这段代码抛出了一个异常,AttributeError, "wtf!",因为A.foo()
正在调用B.foo1()
,它不应该调用A.foo1()
吗?如何强制它调用A.foo1()
(A.foo()
中的任何方法调用都应该调用A.*
)
class A(object):
def foo(self):
print self.foo1()
def foo1(self):
return "foo"
class B(A):
def foo1(self):
raise AttributeError, "wtf!"
def foo(self):
raise AttributeError, "wtf!"
def foo2(self):
super(B, self).foo()
myB = B()
myB.foo2()
【问题讨论】:
您基本上是在要求 Python 抛弃动态性和虚拟方法,并且 不知何故 根据函数的词法定义位置找出跳过属性查找链的部分内容。不会发生。 我认为这是糟糕设计的标志。如果你在你的子类中重写了一个方法,但你不希望它被调用,这难道不是你做错了什么的迹象吗?我认为你应该重新考虑你的类层次结构——也许B
不应该是A
的子类。
我还是有同样的问题。 B.foo2
可以是对A.foo
实现的增强(例如,在B.foo2
中的super
行之后再添加一行)。在这种情况下,您希望A.foo
调用A.foo1
,即按原意调用父实现,然后才对其进行增强。下面的答案围绕在B.foo2
中显式使用A.foo(self)
或更糟糕的是在A.foo
中显式使用A.foo1(self)
。但是答案可能会更改A
,super
是为了解决这个问题,对吧?
【参考方案1】:
它按预期工作,因为世界上 100% 的编程语言都在工作。子类覆盖父类的所有方法。
但是,如果您真的想调用 A.foo1(),您可以这样做(我不能保证)。在任何情况下,您都不能这样做,因为这违反了良好编程的所有原则。
class A(object):
def foo(self):
A.foo1(self)
【讨论】:
【参考方案2】:在代码中:
def foo2(self):
super(B, self).foo()
self 是 B 的一个实例。
当从 A 派生的方法被 B 的实例调用时,它将开始在 B 的命名空间中查找,并且只有在未找到该方法(例如未被 B 覆盖)时才使用来自 A 的实现,但是总是 self 指代 B。在任何时候 self 都不是 A 的实例。
【讨论】:
【参考方案3】:在 A 类中,您需要调用 A
方法并手动传入 self
,而不是调用 self
方法。
这不是正常的做事方式——你应该有一个真的很好的理由这样做。
class A(object):
def foo(self):
print A.foo1(self)
def foo1(self):
return "foo"
class B(A):
def foo1(self):
raise AttributeError, "wtf!"
def foo(self):
raise AttributeError, "wtf!"
def foo2(self):
super(B, self).foo()
myB = B()
myB.foo2()
【讨论】:
【参考方案4】:这里可以看到Python在做什么,但是覆盖的方式有点极端。以 A 类定义 100 个属性而 B 类继承这些属性并添加 1 个属性为例。我们希望能够让 B 的 __init__() 调用 A 的 __init__() 并让 B 的代码只定义它的单个属性。类似地,如果我们在 A 中定义一个 reset() 方法将所有属性设置为零,那么 B 的相应 reset() 方法应该能够只调用 A 的 reset() 方法,然后将单个 B 属性清零不必复制所有 A 的代码。 Python 使本应是面向对象编程的主要优势变得困难。也就是代码的重用。这里最好的选择是避免覆盖我们真正想要重用的方法。如果您想在这里了解 Python 的复杂性,请尝试以下代码:
class X(object):
def __init__ ( self ):
print "X"
self.x = 'x'
self.reset()
print "back to X"
def reset ( self ):
print "reset X"
self.xx = 'xx'
class Y(X):
def __init__ ( self ):
print "Y"
super(Y,self).__init__()
self.y = 'y'
self.reset()
print "back to Y"
def reset ( self ):
print "reset Y"
super(Y,self).reset()
print "back to reset Y"
self.yy = 'yy'
aY = Y()
(为了使这项工作正常进行,请删除类 Y 的 __init__() 中的 self.reset() 调用。)
【讨论】:
这并没有回答问题,只是提供了 Python 中的问题示例。以上是关于调用被覆盖的方法,超类调用被覆盖的方法的主要内容,如果未能解决你的问题,请参考以下文章