如何从基类方法调用重写方法?
派生类可以覆盖其基类的方法 . 因为方法在调用同一对象的其他方法时没有特殊权限,所以调用同一基类中定义的另一个方法的基类方法最终可能会调用覆盖它的派生类的方法 .
这是怎么发生的?有人能用一个简单的例子来说明这个概念吗?
回答(5)
它是如何工作的?
当对类的实例执行属性查找时,类字典 and 将按照特定顺序搜索其基类的字典(请参阅:Method Resolution Order)以获取适当的方法 . 首先发现的是被召唤 .
使用以下 Spam
示例:
class Spam:
def produce_spam(self):
print("spam")
def get_spam(self):
self.produce_spam()
class SuperSpam(Spam):
def produce_spam(self):
print("super spam")
Spam
定义函数 produce_spam
和 get_spam
. 它们存在于 Spam.__dict__
(类命名空间)中 . 通过继承,子类 SuperSpam
可以访问这两种方法 . SuperSpam.produce_spam
不会替换 Spam.produce_spam
,只是在其中一个实例上查找名称 'produce_spam'
时,才会找到它 .
本质上,继承的结果是,如果在对子类进行属性查找之后,在子类的字典中找不到该属性,那么任何基类的字典也将被搜索 .
首次调用函数 get_spam
时:
s = SuperSpam()
s.get_spam()
事件的顺序大致如下:
-
查看
SuperSpam
s__dict__
了解get_spam
. -
因为在
SuperSpam
中找不到它__dict__
查看它的基类(mro
链)的字典 . -
Spam
是mro
链中的下一个,所以get_spam
在Spam
的字典中找到 .
现在,当在 get_spam
的主体中使用 self.produce_spam
查找 produce_spam
时,序列要短得多:
-
查看
SuperSpam
的(self
)__dict__
了解produce_spam
. -
找到它,得到它并调用它 .
produce_spam
首先在 __dict__
中找到,以便获取 .
为了说明它的工作原理,请考虑以下两个类:
class Parent(object):
def eat(self):
print("I don't want to eat that {}.".format(self.takefrompocket()))
def takefrompocket(self):
return 'apple'
def __getattribute__(self, name):
print('Looking for:', name)
method_to_use = object.__getattribute__(self, name)
print('Found method:', method_to_use)
return method_to_use
class Child(Parent):
def takefrompocket(self):
return 'salad'
__getattribute__
方法负责属性查找的新样式类(如python3中的所有类) . 它只是实现 print
每个查找的作用 - normally you don't want to and shouldn't implement it yourself . 如果您真的感兴趣,查找遵循pythons method resolution order (MRO) .
>>> some_kid = Child()
>>> some_kid.eat()
Looking for: eat
Found method: <bound method Parent.eat of <__main__.Child object at 0x0000027BCA4EEA58>>
Looking for: takefrompocket
Found method: <bound method Child.takefrompocket of <__main__.Child object at 0x0000027BCA4EEA58>>
I don't want to eat that salad.
因此,当您想使用 eat
时,它在此示例中使用 Parent.eat
. 但 self.takefrompocket
用于 Child
.
>>> some_parent = Parent()
>>> some_parent.eat()
Looking for: eat
Found method: <bound method Parent.eat of <__main__.Parent object at 0x0000027BCA4EE358>>
Looking for: takefrompocket
Found method: <bound method Parent.takefrompocket of <__main__.Parent object at 0x0000027BCA4EE358>>
I don't want to eat that apple.
这两种方法都取自 Parent
. 继承的类不会(通常)干扰他们的祖先!
2 years ago
这是您请求的示例 . 这打印
chocolate
.打印字符串
chocolate
而不是foo
,因为Derived
会覆盖foo()
函数 . 即使在Base
中定义了bar()
,它最终也会调用foo()
的Derived
实现,而不是Base
实现 .