如何从基类方法中重写方法调用?

时间:2016-12-20 06:31:38

标签: python python-3.x class inheritance

根据docs on inheritance

  

派生类可以覆盖其基类的方法。因为方法在调用同一对象的其他方法时没有特殊权限,所以调用同一基类中定义的另一个方法的基类方法最终可能会调用覆盖它的派生类的方法。

这是怎么发生的?有人能用一个简单的例子来说明这个概念吗?

5 个答案:

答案 0 :(得分:29)

以下是您要求的示例。这会打印chocolate

class Base:
    def foo(self):
        print("foo")
    def bar(self):
        self.foo()

class Derived(Base):
    def foo(self):
        print("chocolate")

d = Derived()
d.bar()  # prints "chocolate"

打印字符串chocolate而不是foo,因为Derived会覆盖foo()函数。即使在bar()中定义了Base,它最终会调用Derived foo()的{​​{1}}实现,而不是Base实现。

答案 1 :(得分:15)

它是如何运作的?

当对类的实例执行属性查找时,类字典将按特定顺序搜索其基类的字典(请参阅:Method Resolution Order)对于适当的方法。找到的内容 first 将被调用。

使用以下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_spamget_spam。它们位于Spam.__dict__(类命名空间)中。通过继承,子类SuperSpam可以访问这两种方法。 SuperSpam.produce_spam不会替换Spam.produce_spam,只有在其中一个实例上查找名称'produce_spam'时才会找到它。

本质上,继承的结果是,如果在对子类进行属性查找之后,在子类中找不到该属性,那么任何基类的字典也将被搜索。字典。

首次使用:

调用函数get_spam
s = SuperSpam()
s.get_spam()

大致的事件序列如下:

  • 查看SuperSpam __dict__ get_spam
  • 由于在SuperSpam s __dict__中找不到它,因此请查看其基类(mro链)的字典。
  • Spam位于mro链的下一位,因此get_spam位于Spam字典中。

现在,produce_spamget_spam的正文中self.produce_spam SuperSpam时,self的序列缩短了:

  • 查看__dict__的{​​{1}} produce_spam produce_spam {/ 1}}。
  • 找到它,得到它并打电话。

__dict__首先在{{1}}中找到,以便获取。

答案 2 :(得分:8)

class Base():
    def m1(self):
        return self.m2()
    def m2(self):
        return 'base'

class Sub(Base):
    def m2(self):
        return 'sub'

b = Base()
s = Sub()
print(b.m1(), s.m1())

打印“base sub”

答案 3 :(得分:1)

为了说明它的工作原理,请考虑以下两个类:

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实现了每个查找的功能 - 通常您不希望也不应该自己实现。如果您真的感兴趣,查找遵循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。继承的类不会(通常)干扰他们的祖先!

答案 4 :(得分:-3)

如果您的子类没有实现该方法,请引发异常!

class Base(object):

    def something (self):
        raise ('Not implemented')