【问题标题】:Call resolution order in Python with multiple inheritance具有多重继承的Python中的调用解析顺序
【发布时间】:2016-11-21 03:25:59
【问题描述】:

我在Youtube 观看 Python 演讲时发现了一个有趣的语言功能。但是,当我尝试运行测试代码时,它不起作用,我想了解原因。

我希望这能打印出来:

Parent
OtherParent

但是我得到了这个:

Parent
Parent

示例代码:

class Parent:
    def get_message(self):
        return "Parent"

class Child(Parent):
    def do_print(self):
        print(super().get_message())

class OtherParent:
    def get_message(self):
        return "OtherParent"

class OtherChild(Child, OtherParent):
    pass

Child().do_print()
OtherChild().do_print()

编辑:在 Windows 上运行,Python 3.5.1,Anaconda 4.0.0(64 位)

【问题讨论】:

  • 你的python版本是多少?
  • print(OtherChild.__mro__) 应该回答你的问题
  • +1 在__mro__ 上解释该行为。有关影响 OtherChild 的 mixins 顺序的答案,请参阅here(简短回答:“MRO 基本上是深度优先,从左到右”)。
  • 另外,here 的一篇文章讨论了同时使用 super() 和 mixins 可能造成的混淆。

标签: python multiple-inheritance


【解决方案1】:

啊,我的朋友指出与 Youtube 上的示例有一点偏差:

class Parent:
    def get_message(self):
        return "Parent"

class Child(Parent):
    def do_print(self):
        print(super().get_message())

class OtherParent(Parent): # <----- Inheritance of Parent makes it work
    def get_message(self):
        return "OtherParent"

class OtherChild(Child, OtherParent):
    pass

Child().do_print()
OtherChild().do_print()

【讨论】:

  • 这并没有真正解释为什么第一个代码没有按预期工作,或者这个更改如何修复它。
  • 不幸的是,我不知道 Python 的内部工作原理,无法详细了解答案。
  • 哦,你是 OP - 那么你可以将其添加到问题中,而不是将其作为答案发布:“如果我让 OtherParent 继承自 @,它会按预期工作987654323@,但我不明白为什么”
  • 是的,尽管我的问题更多是关于“为什么这段代码不能像宣传的那样工作”,而答案是我没有正确实现它。事后看来,我还不如删除了这个问题。
  • 但如果你不明白其中的区别,为什么添加继承会改变行为,那么你可能仍有疑问。
【解决方案2】:

问题的cmets中提到了正确的解释,即来自OtherChild类的MRO(评论中发布的链接:How does the order of mixins affect the derived class?)。

查看OtherChild类的MRO根据不同继承的不同输出:

  1. OtherParent 没有父类:

    class OtherParent():
        def get_message(self):
            return "OtherParent"
    
    print(OtherChild.__mro__)
    Child().do_print()
    OtherChild().do_print()
    

    输出显示ParentOtherParent 之前:

    (<class '__main__.OtherChild'>, <class '__main__.Child'>, <class '__main__.Parent'>, <class '__main__.OtherParent'>, <class 'object'>)
    Parent
    Parent
    
  2. ParentOtherParent的父类:

    class OtherParent(Parent):
        def get_message(self):
            return "OtherParent"
    

    输出显示 OtherParent 现在位于 Parent 之前:

    (<class '__main__.OtherChild'>, <class '__main__.Child'>, <class '__main__.OtherParent'>, <class '__main__.Parent'>, <class 'object'>)
    Parent
    OtherParent
    
  3. 仍然是案例 2,但现在 OtherChild 首先继承自 OtherParent,然后是 Child

    class OtherParent(Parent):
        def get_message(self):
            return "OtherParent"
    
    class OtherChild(OtherParent, Child):
        pass
    

    输出显示OtherParent 再次出现在Parent 之前,但也出现在Child 之前:

    (<class '__main__.OtherChild'>, <class '__main__.OtherParent'>, <class '__main__.Child'>, <class '__main__.Parent'>, <class 'object'>)
    Parent
    Parent
    

也许有人可以解释最后一种乍看不自然的情况。

【讨论】:

  • 父级都没有do_print,它只定义在Child类中,你的意思是get_message吗?但即便如此,我也不太理解解释。
  • @NikoNyrh 然后你为什么接受它?! 也许最好完全删除这个问题(你需要不接受和取消投票这个答案),阅读链接如果您仍然不确定,请再次询问 MRO 订单。就目前而言,这整件事就是一场车祸。
  • 抱歉,在详细阅读之前我太急于接受看似合理的答案:/我无法删除该问题,因为它已经有了答案。下次我会在问这个问题之前做更多的研究。
  • @NikoNyrh 我更新了我的编辑以添加一些具有良好解释的示例(我希望 :))
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-08-09
  • 2014-03-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-15
  • 2014-07-01
相关资源
最近更新 更多