我正在阅读python 3.7文档。我对以下句子感到非常困惑:
“派生类可能会覆盖其基类的方法。由于在调用同一对象的其他方法时这些方法没有特殊特权,因此,调用同一基类中定义的另一个方法的基类方法可能最终会调用a覆盖它的派生类的方法。(对于C ++程序员:Python中的所有方法实际上都是虚拟的。)”
您能否向我展示示例代码:“调用相同基类中定义的另一个方法的基类可能最终会调用覆盖它的派生类的方法”? 这是我的理解:
class A:
def me(self):
print("This is A")
def idet(self):
self.me()
class B(A):
def me(self):
print("this is B")
a = A()
b = B()
b.me()
b.idet()
结果是
this is B
this is B
我不确定是否是这种情况。
最后一个问题是“ Python中的所有方法实际上都是虚拟的”是什么意思? (我熟悉Java,但不熟悉C ++)
答案 0 :(得分:1)
该示例准确地说明了这一原理。 b
是B
的实例,它调用在类ident
中定义的方法A
,该方法又调用me
。由于B
会覆盖me
,因此将调用B
的方法,并打印出this is me
。
在C ++中,默认情况下不能重写方法-您必须将它们声明为virtual
才能获得此行为。在Python(以及您提到的Java)中,这是默认行为。在Java中,您可以通过将方法定义为final
来修改方法,使其不被覆盖。
答案 1 :(得分:1)
派生一个类时,超类的所有方法都将被复制到基类中。当您在基类(或超类)中定义方法时重新定义超类中已经存在的方法时,该方法称为覆盖。当您从子类的基类(或超类)中重写一个方法时,它将有点割断基类中的方法与子类之间的连接。
在您的程序中,您首先要调用b.me()
,这是一个被覆盖的方法。因此,它将执行类me()
中的B
。然后,您获得了b.idet()
,它是基类A
的复制方法;因此,其代码不会更改。但是,当您仔细查看idet()
方法的主体时,它的作用是它将调用从其调用的类的me()
方法。在这种情况下,由于调用该方法的类是类B
,它将从类me()
执行B
方法。
idet()
得到了self.me()
; self
关键字引用,用于在其中写入属性/方法类。
答案 2 :(得分:0)
我认为Python3文档可能还提到过,当类B的实例“ b”引用从类A拉出的方法时,它会传递 itself 放入该方法作为第一个参数(自己)。因此,在由“ b”调用的任何方法中对“自我”的任何引用(包括其继承的方法)都将首先在A类函数之前搜索B类函数,即使派生出“ b”调用的方法也是如此。来自A类。
b.idet()
等效于A.idet(b)
,它调用b.me()
“ 基类的方法,该方法调用在 相同的基类可能最终会调用派生类的方法重写该方法”
我可以看到这似乎有误导性,并且我认为这是因为基类A的方法idet(self)
仅调用在相同基类(A)中定义的另一个方法(如果“自我”指的是A的实例) ,但在上述情况下,当“自我”是指子类B的实例时, idet(self)
并没有真正调用A中定义的另一个方法,而是调用了B中定义的覆盖A的方法。