使用不同的参数在python中调用超类构造函数

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18006310/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 09:42:25  来源:igfitidea点击:

Calling superclass constructors in python with different arguments

pythoninheritanceconstructorarguments

提问by Alexander Gruber

class A():
    def __init__( self, x, y):
        self.x = x
        self.y = y

class B():
    def __init__( self, z=0):
        self.z = z  

class AB(A,B):
    def __init__( self, x, y, z=0):
        ?

How can I make the constructor of AB call the constructors for A and B with the proper arguments?

如何让 AB 的构造函数使用正确的参数调用 A 和 B 的构造函数?

I've tried

我试过了

class AB(A,B):
    def __init__( self, x, y, z=0):
        A.__init__(x,y)
        B.__init__(z)

but this gives me an error.

但这给了我一个错误。

采纳答案by user2357112 supports Monica

You didn't pass self.

你没有通过self

class AB(A, B):
    def __init__(self, x, y, z=0):
        A.__init__(self, x, y)
        B.__init__(self, z)

Note that if this inheritance hierarchy gets more complicated, you'll run into problems with constructors not executing or getting reexecuted. Look into super(and the problemswith super), and don't forget to inherit from objectif you're on 2.x and your class doesn't inherit from anything else.

请注意,如果此继承层次结构变得更加复杂,您将遇到构造函数不执行或重新执行的问题。查看super(以及 )的问题,如果您使用的是 2.x 并且您的类没有从其他任何东西继承super,请不要忘记继承object

回答by ovgolovin

Other answers suggested adding selfto the first parameter.

其他答案建议添加self到第一个参数。

But usually invocations of __init__in parent classes are made by super.

但通常__init__在父类中的调用是由super.

Consider this example:

考虑这个例子:

class A(object):
    def __init__(self, x):
        print('__init__ is called in A')
        self.x = x


class B(object):
    def __init__(self, *args, **kwargs):
        print('__init__ is called in B')
        super(B, self).__init__(*args, **kwargs)


class AB(B, A):
    def __init__(self, *args, **kwargs):
        print('__init__ is called in AB')
        super(AB, self).__init__(*args, **kwargs)

ABclass contains an order in which constructors and initializators should be called:

AB类包含调用构造函数和初始化器的顺序:

>>> AB.__mro__
(<class '__main__.AB'>, <class '__main__.B'>, <class '__main__.A'>, <type 'object'>)

See, that first AB's __init__is invoked, then B's, then A's, and then object's.

看,第一个AB's__init__被调用,然后是B's,然后是A's,然后是object's。

Let's check:

让我们检查:

>>> ab = AB(1)
__init__ is called in AB
__init__ is called in B
__init__ is called in A

But these calls through this chain are made by super. When we type super(AB, self), it means: find then next class after ABin __mro__chain of self.

但是通过这个链的这些调用是由super. 当我们输入 时super(AB, self),它的意思是:AB在 的__mro__链中找到然后下一个类self

Then we should invoke superin B, looking for the next class in the chain after B: super(B, self).

然后我们应该调用superin B,在B:之后寻找链中的下一个类super(B, self)

It's important to use superand not call manually A.__init__(self,...), etc., as it may lead to problems later. Read this for more info.

使用super而不是手动调用A.__init__(self,...)等很重要,因为它可能会导致以后出现问题。阅读本文了解更多信息

So, if you stick with super, then there is a problem. __init__methods in your classes expect different parameters. And you can't know for sure the order in which superwill be invoking methods in these classes. The order is determined by C3 algorithmat the time of class creation. In subclasses another classes may get in-between of the call chain. So you can't have different parameters in __init__, as in this case you will have always to consider all inheritance chain to understand how __init__methods will be called.

所以,如果你坚持super,那么就有问题了。__init__类中的方法需要不同的参数。并且您无法确定super在这些类中调用方法的顺序。顺序由类创建时的C3算法决定。在子类中,另一个类可能会介于调用链之间。所以你不能在 中使用不同的参数__init__,因为在这种情况下,你必须始终考虑所有继承链以了解如何__init__调用方法。

For example, consider adding C(A)and D(B)classes and CDsubclass of them. Then Awill no longer be invoked after B, but after C.

例如,考虑增加C(A)D(B)阶级和CD他们的子类。thenA将不再被调用 after B,而是 after C

class A(object):
    def __init__(self, *args, **kwargs):
        print('__init__ is called in A')
        super(A, self).__init__(*args, **kwargs)


class B(object):
    def __init__(self, *args, **kwargs):
        print('__init__ is called in B')
        super(B, self).__init__(*args, **kwargs)

class AB(B,A):
    def __init__(self, *args, **kwargs):
        print('__init__ is called in AB')
        super(AB, self).__init__(*args, **kwargs)

class C(A):
    def __init__(self, *args, **kwargs):
        print('__init__ is called in C')
        super(C, self).__init__(*args, **kwargs)

class D(B):
    def __init__(self, *args, **kwargs):
        print('__init__ is called in D')
        super(D, self).__init__(*args, **kwargs)


class CD(D,C):
    def __init__(self, *args, **kwargs):
        print('__init__ is called in CD')
        super(CD, self).__init__(*args, **kwargs)

class ABCD(CD,AB):
    def __init__(self, *args, **kwargs):
        print('__init__ is called in ABCD')
        super(ABCD, self).__init__(*args, **kwargs)




>>> abcd = ABCD()
__init__ is called in ABCD
__init__ is called in CD
__init__ is called in D
__init__ is called in AB
__init__ is called in B
__init__ is called in C
__init__ is called in A

So I think it's a good idea to think about using delegationinstead of inheritance here.

所以我认为delegation在这里考虑使用而不是继承是个好主意。

class AB(object):
    def __init__(self, x, y, z=0):
        self.a = A(x,y)
        self.b = B(z)

So, you just create aand binstances of Aand Bclasses inside ABobject. And then may use them as you need through methods by referring to self.aand self.b.

所以,你只需要创建ab实例AB内部类AB对象。然后可以通过引用self.a和 的方法根据需要使用它们self.b

To use or not delegation depends on your case which is not clear from your question. But it may be an option to consider.

使用或不使用委托取决于您的情况,这从您的问题中不清楚。但这可能是一个可以考虑的选择。