Class 没有使用多重继承的 parent class 变量的属性

Class has no attribute of a variable from a parent class using multiple inheretance

这可能已经被问死了,但我真的认为这个问题会对某人有所帮助,因为我真的找不到问题或答案。

我努力将代码简化为最小的结构(忽略狡猾的命名)

首先是问题的堆栈跟踪:

Traceback (most recent call last):
  File "C:\xx\xx\xx\main.py", line 30, in <module>
    DoSomething().method()
  File "C:\xx\xx\xx\main.py", line 27, in method
    self.some_class_method()
  File "C:\xx\xx\xx\main.py", line 12, in some_class_method
    print(self.variable)
AttributeError: 'DoSomething' object has no attribute 'variable'

Process finished with exit code 1

这是失败的代码(从上到下:最低层到最高层,最后调用最高层class(最高就是最多child)):

class ParentConfig:
    def __init__(self):
        pass


class SomeClass:
    def __init__(self):
        super().__init__()
        self.variable = 'value'

    def some_class_method(self):
        print(self.variable)


class Config(ParentConfig, SomeClass):
    def __init__(self):
        super().__init__()
        pass


class DoSomething(Config):
    def __init__(self):
        super().__init__()
        pass

    def method(self):
        self.some_class_method()


DoSomething().method()

我可以通过两种方式让代码工作:

一、去掉'ParentConfig'parentclass

class Config(<removed>, SomeClass):
    def __init__(self):
        super().__init__()
        pass

两个,分别调用__init__s

class Config(ParentConfig, SomeClass):
    def __init__(self):
        ParentConfig().__init__()
        SomeClass().__init__()
        pass

现在,需要明确的是,第二个 'solution' 在此示例中不起作用,但它确实解决了我程序中的问题,很抱歉没有完美的示例。

重点是class'DoSomething'调用方法时不能用self.variable

如果有人可以修复我的示例,使其在单独调用 ParentConfig().__init__()SomeClass().__init__() 时起作用,但在仅使用 super().__init__

时不起作用,则加分

我希望这些信息足够了。与此同时,我将研究一个更好的示例并对其进行编辑。

编辑:

关于 Karl Knechtel 新手回答的 TLDR:

从 ParentClass

中删除 def __init__(self)

或者

在ParentClass

def __init__(self)中添加一个super().__init__()
class ParentConfig:
    def __init__(self):
        pass

问题已经出现了。任何以 ParentConfig 为基础的东西,直接或间接,在遵循 super() 链时都会在这一点停止。

class Config(ParentConfig, SomeClass):

Config(以及直接或间接以它为基础的任何事物)将考虑 ParentConfig before SomeClass when super()Config.__init__ 中调用。 SomeClass.__init__ 因此 不会 被调用,并且 .variable 未设置。

Python处理“钻石继承”问题的方法是super()合作。它不会路由到当前class的直接基地class。它按照实际 self 对象 .

的方法解析顺序路由到 下一个 class

这里应该用在ParentConfig:

class ParentConfig:
    def __init__(self):
        super().__init__()

(或者省略 __init__,因为这是默认行为。)

初始化 Config(或 DoSomething)时,此 super() 调用将路由到 object,而不是 SomeClass,因为想要的。为什么?由于 MRO,您可以在运行时检查它:

>>> Config.__mro__
(<class '__main__.Config'>, <class '__main__.ParentConfig'>, <class '__main__.SomeClass'>, <class 'object'>)
>>> DoSomething.__mro__
(<class '__main__.DoSomething'>, <class '__main__.Config'>, <class '__main__.ParentConfig'>, <class '__main__.SomeClass'>, <class 'object'>)

有关更多详细信息,请参阅 Python's super() considered super!,由 Python 开发团队成员(通常也是一位非常好的老师)撰写的关于该主题的权威文章。