繁体   English   中英

Python“新风格”多重继承结合多个 __init__ 参数

[英]Python “new style” multiple inheritance combined with multiple __init__ arguments

据我了解,如果所有类都使用“新样式”,则会发生这种情况:

class A(object):
    def __init__(self):
        print("Entering A")
        super().__init__()
        print("Leaving A")

class B(object):
    def __init__(self):
        print("Entering B")
        super().__init__()
        print("Leaving B")

class C(A, B):
    def __init__(self):
        print("Entering C")
        super().__init__()
        print("Leaving C")

c = C()
Entering C
Entering A
Entering B
Leaving B
Leaving A
Leaving C

在了解super使用原始对象 ( c ) 的 MRO 之后,为什么Entering/Leaving是这样的。 但是,如果我需要通过一些具体参数是什么AB ,而且在它的参数被按照接收顺序C是不是类似于AB

class A(object):
    def __init__(self, x1, x2):
        print(f"Entering A [x1={x1}, x2={x2}]")
        super().__init__()
        print("Leaving A")

class B(object):
    def __init__(self, y1, y2):
        print(f"Entering B [y1={y1}, y2={y2}]")
        super().__init__()
        print("Leaving B")

class C(A, B):
    def __init__(self, x1, y1, x2, y2):
        print(f"Entering C [x1={x1}, y1={y1}, x2={x2}, y2={y2}]")
        super().__init__()
        print("Leaving C")

c = C('x1', 'y1', 'x2', 'y2')

我可以想到一整天都在传递kwargs ,但我觉得可能有更好的方法。

另外,如果B是库的一部分,因此我们无法更改它并且它使用位置参数,而不是kwargs呢? 在这种情况下,我该怎么办,因为我认为手动弄乱 MRO 不是一个好主意,但同时B的构造函数不会接受kwargs

解决上述问题的正确方法是什么?

好的,这将不再适合评论,但这里似乎存在一些误解。

为了:

class C:
    def __init__(self, arg1=1):
        self.attr1 = arg1

class D(C):
    def __init__(self, arg1):
        super().__init__()

这将产生:

d = D(2)
print(d.attr1)  # prints: 1

因为通过super().__init__()我们调用了 parent 的构造函数,但是我们没有传递任何参数并且它以默认值运行。

或者引用文档来了解super 的作用:

返回一个代理对象,该对象将方法调用委托给类型的父类或兄弟类。 这对于访问在类中被覆盖的继承方法很有用。

即你“只”得到(可能绑定)解析的方法来调用。 不多也不少。 它不会整理您传递的任何参数。 所以你的例子实际上不起作用,因为父母的构造函数都需要一个实例和另外两个参数。

在你的例子中,你可以说:

class A:
    def __init__(self, x1, x2):
        print(f"Entering A [x1={x1}, x2={x2}]")
        print("Leaving A")

class B:
    def __init__(self, y1, y2):
        print(f"Entering B [y1={y1}, y2={y2}]")
        print("Leaving B")

class C(A, B):
    def __init__(self, x1, y1, x2, y2):
        print(f"Entering C [x1={x1}, y1={y1}, x2={x2}, y2={y2}]")
        A.__init__(self, x1, x2)
        B.__init__(self, y1, y2)
        print("Leaving C")

因为您使用相应的特定参数调用每个特定的父构造函数。 文档(同一个地方,关于多继承的第二个常见用例的几段)还包含有关以下内容的提示:

好的设计要求此方法在每种情况下都具有相同的调用签名(因为调用顺序是在运行时确定的,因为该顺序会适应类层次结构的变化,并且因为该顺序可以包括在运行之前未知的兄弟类)。

也就是说,您获得一个代理来调用该方法……然后使用它的参数调用它……这必须是一个固定/稳定的集合,因为您无法预先确定通过该代理访问哪个方法。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM