【问题标题】:Python multiple inheritance is not showing class variables or method of second inherited base classPython多重继承未显示第二个继承基类的类变量或方法
【发布时间】:2018-06-13 10:52:42
【问题描述】:

你好很棒的社区, 作为我课程的一部分,我正在学习使用 python 的 OOPS 概念。我在python中遇到多重继承问题。以下是我的代码:

#!/usr/bin/env python

class Base1(object):
    def __init__(self):
        self.base1var = "this is base1"


class Base2(object):
    def __init__(self):
        self.base2var = "this is base2"

class MainClass(Base1, Base2):
    def __init__(self):
        super(MainClass, self).__init__()


if __name__ == "__main__":
    a = MainClass()
    print a.base1var
    print a.base2var

运行时出现以下错误

print a.base2var
AttributeError: 'MainClass' object has no attribute 'base2var'

如果我交换继承的类的顺序,错误中的变量名会相应改变。

我想调用两个继承类的构造函数时使用super()错了吗?

如何正确地从多个基类继承并使用主类中的变量和方法而不出现此错误?

谢谢。

【问题讨论】:

标签: python oop inheritance


【解决方案1】:

如果您使用super(),您必须一致地使用它以确保调用所有类的方法。你的Base1Base2 类也应该在它们的__init__() 方法中调用super(...).__init__()。这将确保最终调用方法解析顺序中的所有类。

当并非所有__init__() 方法都有一个空参数列表时,这确实有点棘手。在某些时候,super() 会让你打电话给object.__init__(),这从不接受任何参数。问题是,您可能不知道这可能会提前发生在哪些课程中。您可以通过创建一个object 子类来解决此问题,该子类接受__init__() 中的任意数量的参数,并从中派生。该类不需要调用object.__init__(),因为该方法实际上并没有做任何事情(或者,如果你偏执于可能会改变,你可以调用object.__init__()而不使用super())。

一般来说,super() 在处理参数时需要格外小心,因为您可能不知道在方法解析顺序中下一个类将是哪个类,因为您的代码用户可能会使用您的基类组合您没有创建新类预计。所以你需要做一些工作来确保你所有类中的方法签名都是兼容的。

有关更多信息,请参阅 Raymond Hettinger 的开创性文章Python's Super() Considered Super

【讨论】:

    【解决方案2】:

    基本上正在发生的事情是 Python 正在查看父类(及其父类等。请参阅本段末尾的链接)以获取某些方法 __init__。它从左到右读取类,因此它首先看到Base1。由于存在Base1.__init__,因此调用了该方法。在this answer 阅读更详细的说明。

    我相信调用所有适当方法的唯一方法是手动调用

    class MainClass(Base1, Base2):
        def __init__(self):
            Base1.__init__(self)
            Base2.__init__(self)
    

    然后

    a = MainClass()
    print(a.base1var)
    print(a.base2var)
    

    打印

    this is base1
    this is base2
    

    【讨论】:

    • 不是父类;它正在选择 MRO 中的下一个方法,其中可能包括 MainClass 静态未知的类。
    【解决方案3】:

    您需要向 Base1 添加一个 super 调用,以便 Base2 的 __init__ 将在 Base1 之后被调用。您还可以向 Base2 添加super 调用。没必要,但不会有伤害。

    class Base1(object):
        def __init__(self):
            super(Base1, self).__init__()
            self.base1var = "this is base1"
    
    class Base2(object):
        def __init__(self):
            #super(Base2, self).__init__()
            self.base2var = "this is base2"
    
    class MainClass(Base1, Base2):
        def __init__(self):
            super(MainClass, self).__init__()
    
    
    if __name__ == "__main__":
        a = MainClass()
        print a.base1var
        print a.base2var
    

    输出

    this is base1
    this is base2
    

    顺便说一句,您真的应该使用 Python 3。super 在现代 Python 中要好得多。 :)

    【讨论】:

    • 可以说,super 在 Python 2 中更容易理解;因为你不能放弃论点,你不得不(至少一点点)思考为什么特定的论点是必要的。 Python 3 可能会让人想知道为什么 super 完全是可调用的,而不仅仅是引用当前类的关键字。 (不过,对于绝大多数用例来说,在 Python 3 中无疑更方便。)
    • @chepner 我想是的。 Python 3 中的super 可能有点 神奇。 :)
    【解决方案4】:

    使用 super 但不是为了那个目标是正确的。解释super 我修改了你的代码

    #!/usr/bin/env python
    
    class Base1(object):
        def __init__(self):
            self.base1var = "this is base1"
    
    
    class Base2(object):
        def __init__(self):
            self.base2var = "this is base2"
    
    class MainClass(Base2, Base1):
        def __init__(self):
            super(MainClass, self).__init__()
    
    
    if __name__ == "__main__":
        a = MainClass()
        print (a.base2var)
    

    比你有的

    this is base2
    

    【讨论】:

    • super 甚至不一定要选择父母;它使用 MRO 中的 next 方法,它甚至可能是静态未知的。
    • @chepner 我同意将尝试重新制定。
    【解决方案5】:

    Base1 __init__ 覆盖 Base2 __init__.py,因此永远不会创建 base2var

    你应该使用super,见How does Python's super() work with multiple inheritance?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-08
      • 1970-01-01
      • 2020-11-11
      • 1970-01-01
      • 2017-11-25
      • 2015-03-10
      相关资源
      最近更新 更多