使用多重继承调用父类__init__,这是正确的方法吗?

时间:2021-01-12 18:21:54

Say I have a multiple inheritance scenario:

假设我有一个多继承场景:

class A(object):
    # code for A here

class B(object):
    # code for B here

class C(A, B):
    def __init__(self):
        # What's the right code to write here to ensure 
        # A.__init__ and B.__init__ get called?

There's two typical approaches to writing C's __init__:

编写C的__init__有两种典型的方法:

  1. (old-style) ParentClass.__init__(self)
  2. (旧式)ParentClass .__ init __(self)
  3. (newer-style) super(DerivedClass, self).__init__()
  4. (较新式)super(DerivedClass,self).__ init __()

However, in either case, if the parent classes (A and B) don't follow the same convention, then the code will not work correctly (some may be missed, or get called multiple times).

但是,在任何一种情况下,如果父类(A和B)不遵循相同的约定,则代码将无法正常工作(某些可能会被遗漏,或被多次调用)。

So what's the correct way again? It's easy to say "just be consistent, follow one or the other", but if A or B are from a 3rd party library, what then? Is there an approach that can ensure that all parent class constructors get called (and in the correct order, and only once)?

那么又有什么正确的方法呢?很容易说“只是保持一致,遵循一个或另一个”,但如果A或B来自第三方库,那么呢?是否有一种方法可以确保所有父类构造函数被调用(并且以正确的顺序,只有一次)?

Edit: to see what I mean, if I do:

编辑:看看我的意思,如果我这样做:

class A(object):
    def __init__(self):
        print("entering A")
        super(A, self).__init__()
        print("leaving A")

class B(object):
    def __init__(self):
        print("entering B")
        super(B, self).__init__()
        print("leaving B")

class C(A, B):
    def __init__(self):
        print("entering c")
        A.__init__(self)
        B.__init__(self)
        print("leaving c")

Then I get:

然后我得到:

entering c
entering A
entering B
leaving B
leaving A
entering B
leaving B
leaving c

Note that B's init gets called twice. If I do:

请注意,B的init被调用两次。如果我做:

class A(object):
    def __init__(self):
        print("entering A")
        print("leaving A")

class B(object):
    def __init__(self):
        print("entering B")
        super(B, self).__init__()
        print("leaving B")

class C(A, B):
    def __init__(self):
        print("entering c")
        super(C, self).__init__()
        print("leaving c")

Then I get:

然后我得到:

entering c
entering A
leaving A
leaving c

Note that B's init never gets called. So it seems that unless I know/control the init's of the classes I inherit from (A and B) I cannot make a safe choice for the class I'm writing (C).

请注意,B的init永远不会被调用。所以看起来,除非我知道/控制我从(A和B)继承的类的init,否则我无法为我写的类(C)做出安全的选择。

5 个解决方案

#1


44  

Both ways work fine. The approach using super() leads to greater flexibility for subclasses.

两种方式都很好。使用super()的方法为子类带来了更大的灵活性。

In the direct call approach, C.__init__ can call both A.__init__ and B.__init__.

在直接调用方法中,C .__ init__可以同时调用A .__ init__和B .__ init__。

When using super(), the classes need to be designed for cooperative multiple inheritance where C calls super, which invokes A's code which will also call super which invokes B's code. See http://rhettinger.wordpress.com/2011/05/26/super-considered-super for more detail on what can be done with super.

当使用super()时,类需要设计用于协作多继承,其中C调用super,它调用A的代码,该代码也将调用调用B代码的super。有关可以使用super执行的操作的更多详细信息,请参见http://rhettinger.wordpress.com/2011/05/26/super-considered-super。

[Response question as later edited]

[后面编辑的回复问题]

So it seems that unless I know/control the init's of the classes I inherit from (A and B) I cannot make a safe choice for the class I'm writing (C).

所以看起来,除非我知道/控制我从(A和B)继承的类的init,否则我无法为我写的类(C)做出安全的选择。

The referenced article shows how to handle this situation by adding a wrapper class around A and B. There is a worked-out example in the section titled "How to Incorporate a Non-cooperative Class".

引用的文章展示了如何通过在A和B周围添加包装类来处理这种情况。在标题为“如何合并非合作类”的部分中有一个经过深思熟虑的示例。

One might wish that multiple inheritance were easier, letting you effortlessly compose Car and Airplane classes to get a FlyingCar, but the reality is that separately designed components often need adapters or wrappers before fitting together as seamlessly as we would like :-)

有人可能希望多继承更容易,让你毫不费力地组成Car和Airplane类来获得FlyingCar,但实际情况是,单独设计的组件通常需要适配器或包装器才能像我们希望的那样无缝地装配在一起:-)

One other thought: if you're unhappy with composing functionality using multiple inheritance, you can use composition for complete control over which methods get called on which occasions.

另一个想法是:如果您对使用多重继承编写功能感到不满意,可以使用合成来完全控制在哪些场合调用哪些方法。

#2


6  

The answer to your question depends on one very important aspect: Are your base classes designed for multiple inheritance?

您的问题的答案取决于一个非常重要的方面:您的基类是否设计用于多重继承?

There are 3 different scenarios:

有3种不同的场景:

  1. The base classes are unrelated, standalone classes.

    If your base classes are separate entities that are capable of functioning independently and they don't know each other, they're not designed for multiple inheritance.

    如果您的基类是能够独立运行且彼此不了解的独立实体,则它们不是为多重继承而设计的。

    In this case, you will have to call each parent constructor manually. This is easier without super.

    在这种情况下,您必须手动调用每个父构造函数。没有超级,这更容易。

    Example:

    例:

    class Foo:
        def __init__(self):
            self.foo = 'foo'
    
    class Bar:
        def __init__(self, bar):
            self.bar = bar
    
    class FooBar(Foo, Bar):
        def __init__(self, bar='bar'):
            Foo.__init__(self)  # explicit calls without super
            Bar.__init__(self, bar)
    
            # To get the same results with `super`, you'd have to do this:
            #   super().__init__()
            #   super(Foo, self).__init__(bar)
            # Which is obviously much less intuitive.
    

    Important: Notice that neither Foo nor Bar calls super().__init__()! This is why your code didn't work correctly. Because of the way diamond inheritance works in python, classes whose base class is object should not call super().__init__(). As you've noticed, doing so would break multiple inheritance because you end up calling another class's __init__ rather than object.__init__().

    重要提示:请注意,Foo和Bar都不会调用super().__ init __()!这就是您的代码无法正常工作的原因。由于钻石继承在python中的工作方式,基类为object的类不应该调用super().__ init __()。正如您所注意到的那样,这样做会破坏多重继承,因为您最终会调用另一个类的__init__而不是object .__ init __()。

    This also means that you should never write a class that inherits from object and doesn't have an __init__ method. Not defining a __init__ method at all has the same effect as calling super().__init__(). If your class inherits directly from object, make sure to add an empty constructor like so:

    这也意味着你永远不应该编写一个继承自object并且没有__init__方法的类。根本不定义__init__方法与调用super().__ init __()具有相同的效果。如果您的类直接从object继承,请确保添加如下的空构造函数:

    class Base(object):
        def __init__(self):
            pass
    
  2. One of the classes is a mixin.

    A mixin is a class that's designed to be used with multiple inheritance. This means we don't have to call both parent constructors manually, because the mixin will automatically call the 2nd constructor for us. Since we only have to call a single constructor this time, we can do so with super to avoid having to hard-code the parent class's name.

    mixin是一个专门用于多重继承的类。这意味着我们不必手动调用两个父构造函数,因为mixin将自动为我们调用第二个构造函数。由于我们这次只需要调用一个构造函数,因此我们可以使用super来避免必须对父类的名称进行硬编码。

    Example:

    例:

    class FooMixin:
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            self.foo = 'foo'
    
    class Bar:
        def __init__(self, bar):
            self.bar = bar
    
    class FooBar(FooMixin, Bar):
        def __init__(self, bar='bar'):
            super().__init__(bar)  # a single call is enough to invoke
                                   # all parent constructors
    
            # NOTE: `FooMixin.__init__(self, bar)` would also work, but isn't
            # recommended because we don't want to hard-code the parent class.
    

    The important details here are:

    这里的重要细节是:

    • The mixin calls super().__init__() and passes through any arguments it receives.
    • mixin调用super().__ init __()并传递它接收的任何参数。
    • The subclass inherits from the mixin first: class FooBar(FooMixin, Bar). If the order of the base classes is wrong, the mixin's constructor will never be called.
    • 子类首先从mixin继承:class FooBar(FooMixin,Bar)。如果基类的顺序错误,则永远不会调用mixin的构造函数。
  3. All base classes are designed for cooperative inheritance.

    Classes designed for cooperative inheritance are a lot like mixins: They pass through all unused arguments to the next class. Like before, we just have to call super().__init__() and all parent constructors will be chain-called.

    为协作继承而设计的类很像mixins:它们将所有未使用的参数传递给下一个类。像以前一样,我们只需调用super().__ init __(),所有父构造函数都将被链调用。

    Example:

    例:

    class CoopFoo:
        def __init__(self, **kwargs):
            super().__init__(**kwargs)
            self.foo = 'foo'
    
    class CoopBar:
        def __init__(self, bar, **kwargs):
            super().__init__(**kwargs)
            self.bar = bar
    
    class CoopFooBar(CoopFoo, CoopBar):
        def __init__(self, bar='bar'):
            super().__init__(bar=bar)  # pass all arguments on as keyword
                                       # arguments to avoid problems with
                                       # positional arguments and the order
                                       # of the parent classes
    

    In this case, the order of the parent classes doesn't matter. We might as well inherit from CoopBar first, and the code would still work the same. But that's only true because all arguments are passed as keyword arguments. Using positional arguments would make it easy to get the order of the arguments wrong, so it's customary for cooperative classes to accept only keyword arguments.

    在这种情况下,父类的顺序无关紧要。我们最好先从CoopBar继承,代码仍然可以正常工作。但这是唯一的,因为所有参数都作为关键字参数传递。使用位置参数可以很容易地使参数的顺序错误,因此合作类通常只接受关键字参数。

    This is also an exception to the rule I mentioned earlier: Both CoopFoo and CoopBar inherit from object, but they still call super().__init__(). If they didn't, there would be no cooperative inheritance.

    这也是我之前提到的规则的一个例外:CoopFoo和CoopBar都继承自object,但它们仍然调用super().__ init __()。如果他们不这样做,就没有合作继承权。

Bottom line: The correct implementation depends on the classes you're inheriting from.

底线:正确的实现取决于您继承的类。

The constructor is part of a class's public interface. If the class is designed as a mixin or for cooperative inheritance, that must be documented. If the docs don't mention anything of the sort, it's safe to assume that the class isn't designed for multiple inheritance and you have to call each parent class's constructor explicitly (without super).

构造函数是类的公共接口的一部分。如果将类设计为mixin或用于协作继承,则必须记录该类。如果文档没有提及任何类型的东西,可以安全地假设该类不是为多重继承而设计的,并且您必须显式调用每个父类的构造函数(不使用super)。

#3


3  

This article helps to explain cooperative multiple inheritance:

本文有助于解释协作多重继承:

http://www.artima.com/weblogs/viewpost.jsp?thread=281127

http://www.artima.com/weblogs/viewpost.jsp?thread=281127

It mentions the useful method mro() that shows you the method resolution order. In your 2nd example, where you call super in A, the super call continues on in MRO. The next class in the order is B, this is why B's init is called the first time.

它提到了有用的方法mro(),它显示了方法解析顺序。在您的第二个示例中,您在A中呼叫超级,超级呼叫在MRO中继续。顺序中的下一个类是B,这就是为什么第一次调用B的init。

Here's a more technical article from the official python site:

这是来自官方python网站的更多技术文章:

http://www.python.org/download/releases/2.3/mro/

http://www.python.org/download/releases/2.3/mro/

#4


2  

If you are multiply sub-classing classes from third party libraries, then no, there is no blind approach to calling the base class __init__ methods (or any other methods) that actually works regardless of how the base classes are programmed.

如果你是来自第三方库的多级子类,那么不,没有盲目的方法来调用实际工作的基类__init__方法(或任何其他方法),无论基类如何编程。

super makes it possible to write classes designed to cooperatively implement methods as part of complex multiple inheritance trees which need not be known to the class author. But there's no way to use it to correctly inherit from arbitrary classes that may or may not use super.

super使得编写用于协作实现方法的类成为可能,这些类是复杂的多继承树的一部分,这些树不需要为类作者所知。但是没有办法使用它来正确地继承可能使用或不使用super的任意类。

Essentially, whether a class is designed to be sub-classed using super or with direct calls to the base class is a property which is part of the class' "public interface", and it should be documented as such. If you're using third-party libraries in the way that the library author expected and the library has reasonable documentation, it would normally tell you what you are required to do to subclass particular things. If not, then you'll have to look at the source code for the classes you're sub-classing and see what their base-class-invocation convention is. If you're combining multiple classes from one or more third-party libraries in a way that the library authors didn't expect, then it may not be possible to consistently invoke super-class methods at all; if class A is part of a hierarchy using super and class B is part of a hierarchy that doesn't use super, then neither option is guaranteed to work. You'll have to figure out a strategy that happens to work for each particular case.

从本质上讲,类是否设计为使用超级或直接调用基类进行子类化是属于类“公共接口”的一部分的属性,并且应该如此记录。如果您以库作者期望的方式使用第三方库并且库具有合理的文档,则通常会告诉您要对特定事物进行子类化所需的操作。如果没有,那么你将不得不查看你要进行子类化的类的源代码,看看他们的基类调用约定是什么。如果您以一种图书馆作者不期望的方式组合来自一个或多个第三方库的多个类,那么可能根本无法一致地调用超类方法;如果A类是使用super的层次结构的一部分而B类是不使用super的层次结构的一部分,那么这两个选项都不能保证工作。您必须找出适用于每个特定案例的策略。

#5


0  

As Raymond said in his answer, a direct call to A.__init__ and B.__init__ works fine, and your code would be readable.

正如Raymond在他的回答中所说,直接调用A .__ init__和B .__ init__可以正常工作,并且您的代码是可读的。

However, it does not use the inheritance link between C and those classes. Exploiting that link gives you more consistancy and make eventual refactorings easier and less error-prone. An example of how to do that:

但是,它不使用C和那些类之间的继承链接。利用该链接可以提供更多的实用性,并使最终的重构更容易,更不容易出错。如何做到这一点的一个例子:

class C(A, B):
    def __init__(self):
        print("entering c")
        for base_class in C.__bases__:  # (A, B)
             base_class.__init__(self)
        print("leaving c")

#1


44  

Both ways work fine. The approach using super() leads to greater flexibility for subclasses.

两种方式都很好。使用super()的方法为子类带来了更大的灵活性。

In the direct call approach, C.__init__ can call both A.__init__ and B.__init__.

在直接调用方法中,C .__ init__可以同时调用A .__ init__和B .__ init__。

When using super(), the classes need to be designed for cooperative multiple inheritance where C calls super, which invokes A's code which will also call super which invokes B's code. See http://rhettinger.wordpress.com/2011/05/26/super-considered-super for more detail on what can be done with super.

当使用super()时,类需要设计用于协作多继承,其中C调用super,它调用A的代码,该代码也将调用调用B代码的super。有关可以使用super执行的操作的更多详细信息,请参见http://rhettinger.wordpress.com/2011/05/26/super-considered-super。

[Response question as later edited]

[后面编辑的回复问题]

So it seems that unless I know/control the init's of the classes I inherit from (A and B) I cannot make a safe choice for the class I'm writing (C).

所以看起来,除非我知道/控制我从(A和B)继承的类的init,否则我无法为我写的类(C)做出安全的选择。

The referenced article shows how to handle this situation by adding a wrapper class around A and B. There is a worked-out example in the section titled "How to Incorporate a Non-cooperative Class".

引用的文章展示了如何通过在A和B周围添加包装类来处理这种情况。在标题为“如何合并非合作类”的部分中有一个经过深思熟虑的示例。

One might wish that multiple inheritance were easier, letting you effortlessly compose Car and Airplane classes to get a FlyingCar, but the reality is that separately designed components often need adapters or wrappers before fitting together as seamlessly as we would like :-)

有人可能希望多继承更容易,让你毫不费力地组成Car和Airplane类来获得FlyingCar,但实际情况是,单独设计的组件通常需要适配器或包装器才能像我们希望的那样无缝地装配在一起:-)

One other thought: if you're unhappy with composing functionality using multiple inheritance, you can use composition for complete control over which methods get called on which occasions.

另一个想法是:如果您对使用多重继承编写功能感到不满意,可以使用合成来完全控制在哪些场合调用哪些方法。

#2


6  

The answer to your question depends on one very important aspect: Are your base classes designed for multiple inheritance?

您的问题的答案取决于一个非常重要的方面:您的基类是否设计用于多重继承?

There are 3 different scenarios:

有3种不同的场景:

  1. The base classes are unrelated, standalone classes.

    If your base classes are separate entities that are capable of functioning independently and they don't know each other, they're not designed for multiple inheritance.

    如果您的基类是能够独立运行且彼此不了解的独立实体,则它们不是为多重继承而设计的。

    In this case, you will have to call each parent constructor manually. This is easier without super.

    在这种情况下,您必须手动调用每个父构造函数。没有超级,这更容易。

    Example:

    例:

    class Foo:
        def __init__(self):
            self.foo = 'foo'
    
    class Bar:
        def __init__(self, bar):
            self.bar = bar
    
    class FooBar(Foo, Bar):
        def __init__(self, bar='bar'):
            Foo.__init__(self)  # explicit calls without super
            Bar.__init__(self, bar)
    
            # To get the same results with `super`, you'd have to do this:
            #   super().__init__()
            #   super(Foo, self).__init__(bar)
            # Which is obviously much less intuitive.
    

    Important: Notice that neither Foo nor Bar calls super().__init__()! This is why your code didn't work correctly. Because of the way diamond inheritance works in python, classes whose base class is object should not call super().__init__(). As you've noticed, doing so would break multiple inheritance because you end up calling another class's __init__ rather than object.__init__().

    重要提示:请注意,Foo和Bar都不会调用super().__ init __()!这就是您的代码无法正常工作的原因。由于钻石继承在python中的工作方式,基类为object的类不应该调用super().__ init __()。正如您所注意到的那样,这样做会破坏多重继承,因为您最终会调用另一个类的__init__而不是object .__ init __()。

    This also means that you should never write a class that inherits from object and doesn't have an __init__ method. Not defining a __init__ method at all has the same effect as calling super().__init__(). If your class inherits directly from object, make sure to add an empty constructor like so:

    这也意味着你永远不应该编写一个继承自object并且没有__init__方法的类。根本不定义__init__方法与调用super().__ init __()具有相同的效果。如果您的类直接从object继承,请确保添加如下的空构造函数:

    class Base(object):
        def __init__(self):
            pass
    
  2. One of the classes is a mixin.

    A mixin is a class that's designed to be used with multiple inheritance. This means we don't have to call both parent constructors manually, because the mixin will automatically call the 2nd constructor for us. Since we only have to call a single constructor this time, we can do so with super to avoid having to hard-code the parent class's name.

    mixin是一个专门用于多重继承的类。这意味着我们不必手动调用两个父构造函数,因为mixin将自动为我们调用第二个构造函数。由于我们这次只需要调用一个构造函数,因此我们可以使用super来避免必须对父类的名称进行硬编码。

    Example:

    例:

    class FooMixin:
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            self.foo = 'foo'
    
    class Bar:
        def __init__(self, bar):
            self.bar = bar
    
    class FooBar(FooMixin, Bar):
        def __init__(self, bar='bar'):
            super().__init__(bar)  # a single call is enough to invoke
                                   # all parent constructors
    
            # NOTE: `FooMixin.__init__(self, bar)` would also work, but isn't
            # recommended because we don't want to hard-code the parent class.
    

    The important details here are:

    这里的重要细节是:

    • The mixin calls super().__init__() and passes through any arguments it receives.
    • mixin调用super().__ init __()并传递它接收的任何参数。
    • The subclass inherits from the mixin first: class FooBar(FooMixin, Bar). If the order of the base classes is wrong, the mixin's constructor will never be called.
    • 子类首先从mixin继承:class FooBar(FooMixin,Bar)。如果基类的顺序错误,则永远不会调用mixin的构造函数。
  3. All base classes are designed for cooperative inheritance.

    Classes designed for cooperative inheritance are a lot like mixins: They pass through all unused arguments to the next class. Like before, we just have to call super().__init__() and all parent constructors will be chain-called.

    为协作继承而设计的类很像mixins:它们将所有未使用的参数传递给下一个类。像以前一样,我们只需调用super().__ init __(),所有父构造函数都将被链调用。

    Example:

    例:

    class CoopFoo:
        def __init__(self, **kwargs):
            super().__init__(**kwargs)
            self.foo = 'foo'
    
    class CoopBar:
        def __init__(self, bar, **kwargs):
            super().__init__(**kwargs)
            self.bar = bar
    
    class CoopFooBar(CoopFoo, CoopBar):
        def __init__(self, bar='bar'):
            super().__init__(bar=bar)  # pass all arguments on as keyword
                                       # arguments to avoid problems with
                                       # positional arguments and the order
                                       # of the parent classes
    

    In this case, the order of the parent classes doesn't matter. We might as well inherit from CoopBar first, and the code would still work the same. But that's only true because all arguments are passed as keyword arguments. Using positional arguments would make it easy to get the order of the arguments wrong, so it's customary for cooperative classes to accept only keyword arguments.

    在这种情况下,父类的顺序无关紧要。我们最好先从CoopBar继承,代码仍然可以正常工作。但这是唯一的,因为所有参数都作为关键字参数传递。使用位置参数可以很容易地使参数的顺序错误,因此合作类通常只接受关键字参数。

    This is also an exception to the rule I mentioned earlier: Both CoopFoo and CoopBar inherit from object, but they still call super().__init__(). If they didn't, there would be no cooperative inheritance.

    这也是我之前提到的规则的一个例外:CoopFoo和CoopBar都继承自object,但它们仍然调用super().__ init __()。如果他们不这样做,就没有合作继承权。

Bottom line: The correct implementation depends on the classes you're inheriting from.

底线:正确的实现取决于您继承的类。

The constructor is part of a class's public interface. If the class is designed as a mixin or for cooperative inheritance, that must be documented. If the docs don't mention anything of the sort, it's safe to assume that the class isn't designed for multiple inheritance and you have to call each parent class's constructor explicitly (without super).

构造函数是类的公共接口的一部分。如果将类设计为mixin或用于协作继承,则必须记录该类。如果文档没有提及任何类型的东西,可以安全地假设该类不是为多重继承而设计的,并且您必须显式调用每个父类的构造函数(不使用super)。

#3


3  

This article helps to explain cooperative multiple inheritance:

本文有助于解释协作多重继承:

http://www.artima.com/weblogs/viewpost.jsp?thread=281127

http://www.artima.com/weblogs/viewpost.jsp?thread=281127

It mentions the useful method mro() that shows you the method resolution order. In your 2nd example, where you call super in A, the super call continues on in MRO. The next class in the order is B, this is why B's init is called the first time.

它提到了有用的方法mro(),它显示了方法解析顺序。在您的第二个示例中,您在A中呼叫超级,超级呼叫在MRO中继续。顺序中的下一个类是B,这就是为什么第一次调用B的init。

Here's a more technical article from the official python site:

这是来自官方python网站的更多技术文章:

http://www.python.org/download/releases/2.3/mro/

http://www.python.org/download/releases/2.3/mro/

#4


2  

If you are multiply sub-classing classes from third party libraries, then no, there is no blind approach to calling the base class __init__ methods (or any other methods) that actually works regardless of how the base classes are programmed.

如果你是来自第三方库的多级子类,那么不,没有盲目的方法来调用实际工作的基类__init__方法(或任何其他方法),无论基类如何编程。

super makes it possible to write classes designed to cooperatively implement methods as part of complex multiple inheritance trees which need not be known to the class author. But there's no way to use it to correctly inherit from arbitrary classes that may or may not use super.

super使得编写用于协作实现方法的类成为可能,这些类是复杂的多继承树的一部分,这些树不需要为类作者所知。但是没有办法使用它来正确地继承可能使用或不使用super的任意类。

Essentially, whether a class is designed to be sub-classed using super or with direct calls to the base class is a property which is part of the class' "public interface", and it should be documented as such. If you're using third-party libraries in the way that the library author expected and the library has reasonable documentation, it would normally tell you what you are required to do to subclass particular things. If not, then you'll have to look at the source code for the classes you're sub-classing and see what their base-class-invocation convention is. If you're combining multiple classes from one or more third-party libraries in a way that the library authors didn't expect, then it may not be possible to consistently invoke super-class methods at all; if class A is part of a hierarchy using super and class B is part of a hierarchy that doesn't use super, then neither option is guaranteed to work. You'll have to figure out a strategy that happens to work for each particular case.

从本质上讲,类是否设计为使用超级或直接调用基类进行子类化是属于类“公共接口”的一部分的属性,并且应该如此记录。如果您以库作者期望的方式使用第三方库并且库具有合理的文档,则通常会告诉您要对特定事物进行子类化所需的操作。如果没有,那么你将不得不查看你要进行子类化的类的源代码,看看他们的基类调用约定是什么。如果您以一种图书馆作者不期望的方式组合来自一个或多个第三方库的多个类,那么可能根本无法一致地调用超类方法;如果A类是使用super的层次结构的一部分而B类是不使用super的层次结构的一部分,那么这两个选项都不能保证工作。您必须找出适用于每个特定案例的策略。

#5


0  

As Raymond said in his answer, a direct call to A.__init__ and B.__init__ works fine, and your code would be readable.

正如Raymond在他的回答中所说,直接调用A .__ init__和B .__ init__可以正常工作,并且您的代码是可读的。

However, it does not use the inheritance link between C and those classes. Exploiting that link gives you more consistancy and make eventual refactorings easier and less error-prone. An example of how to do that:

但是,它不使用C和那些类之间的继承链接。利用该链接可以提供更多的实用性,并使最终的重构更容易,更不容易出错。如何做到这一点的一个例子:

class C(A, B):
    def __init__(self):
        print("entering c")
        for base_class in C.__bases__:  # (A, B)
             base_class.__init__(self)
        print("leaving c")