首页 文章

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

提问于
浏览
23

根据docs on inheritance

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

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

5 回答

  • 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() 函数 . 即使在 Base 中定义了 bar() ,它最终也会调用 foo()Derived 实现,而不是 Base 实现 .

  • 15

    它是如何工作的?

    当对类的实例执行属性查找时,类字典 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_spamget_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 链)的字典 .

    • Spammro 链中的下一个,所以 get_spamSpam 的字典中找到 .

    现在,当在 get_spam 的主体中使用 self.produce_spam 查找 produce_spam 时,序列要短得多:

    • 查看 SuperSpam 的( self__dict__ 了解 produce_spam .

    • 找到它,得到它并调用它 .

    produce_spam 首先在 __dict__ 中找到,以便获取 .

  • -3
    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”

  • 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 每个查找的作用 - 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 . 继承的类不会(通常)干扰他们的祖先!

  • 8

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

    class Base(object):
    
        def something (self):
            raise ('Not implemented')
    

相关问题