调用被覆盖的方法,超类调用被覆盖的方法

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)。但是答案可能会更改Asuper 是为了解决这个问题,对吧? 【参考方案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 中的问题示例。

以上是关于调用被覆盖的方法,超类调用被覆盖的方法的主要内容,如果未能解决你的问题,请参考以下文章

超类中的私有final可以被覆盖吗?

什么体现了类的多态性?

多态小记

java如何调用父类的父类中被覆盖的方法

java多态加深

电话和Callvirt