用多个继承来调用父类__init__,正确的方法是什么?

发布于 2025-02-01 10:59:39 字数 1990 浏览 5 评论 0原文

假设我有一个多个继承方案:

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?

有两种典型的方法。

  1. 编写c's __ INT __ INT __ :( old-code)parent> parent> parentclass .__ init __(self)
  2. (新型)super(derivedClass,self)

。 >)不遵循同一惯例,那么代码将无法正常工作(有些可能会错过一些,或多次被调用)。

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

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

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")

然后得到:

Entering C
Entering A
Entering B
Leaving B
Leaving A
Entering B
Leaving B
Leaving C

请注意,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")

然后我得到:

Entering C
Entering A
Leaving A
Leaving C

请注意,b的init永远不会被调用。因此,似乎除非我知道/控制我从(ab)继承的类的初始化,我无法为正在写的课程做出安全的选择( C)。

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__:

  1. (old-style) ParentClass.__init__(self)
  2. (newer-style) 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).

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)?

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:

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).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

蓝眼睛不忧郁 2025-02-08 10:59:39

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

有3种不同的方案:

  1. 基类是无关的,独立的类。

    如果您的基类是能够独立运作并且他们彼此不认识的独立实体,则它们不是为多个继承而设计的。示例:

     类foo:
        def __init __(自我):
            self.foo ='foo'
    
    班级:
        def __init __(self,bar):
            self.bar = bar
     

    重要:请注意,foo not bar call call super().__ INT __()!这就是为什么您的代码无法正常工作的原因。由于钻石继承在python中的工作方式,基类是对象不应调用super().__ INT __() 。正如您注意到的那样,这样做会破坏多个继承,因为您最终调用了另一类的__ INT __而不是Object .__ INT __()免责声明:避免super()。在Python社区中达成共识。 rel =“ noreferrer”>适配器如果类不像您预期​​的那样行事。)

    这也意味着您切勿编写从对象继承的类,并且没有__ INIT __方法。不能定义__ Init __方法与调用super().__ INT __()的效果相同。如果您的类直接从对象继承,请确保添加一个空的构造函数:

     类基础(对象):
        def __init __(自我):
            经过
     

    无论如何,在这种情况下,您必须手动致电每个父构建器。有两种方法:

    • 没有超级

       类Foobar(foo,bar):
          def __init __(self,bar ='bar'):
              foo .__ init __(self)#明确通话没有超级
              bar .__ init __(self,bar)
       
    • 使用超级

       类Foobar(foo,bar):
          def __init __(self,bar ='bar'):
              super().__ init __()#this this呼叫所有构造函数
              super(foo,self).__ init __(bar)#foo up后调用所有构造函数
                                              #到酒吧
       

    这两种方法中的每种都有其自身的优势和缺点。如果您使用super,您的类将支持依赖项注入。另一方面,犯错很容易。例如,如果更改foobar(例如类Foobar(bar,foo))的顺序,则必须更新超级匹配调用。没有超级您不必为此担心,并且代码更具可读性。

  2. 其中一个是混合物。

    a mixin 是一类是< em>设计可与多个继承一起使用。这意味着我们不必手动调用两个父构造函数,因为Mixin会自动为我们调用第二个构造函数。由于这次我们只需要调用单个构造函数,因此我们可以使用super来避免必须硬编码父类的名称。

    示例:

     类foomixin:
        def __init __(self, *args,** kwargs):
            super()。
            self.foo ='foo'
    
    班级:
        def __init __(self,bar):
            self.bar = bar
    
    Foobar类(Foomixin,bar):
        def __init __(self,bar ='bar'):
            super().__ INIT __(bar)#单个电话足以调用
                                   #所有父构建体
    
            #注意:`foomixin .__ init __(self,bar)`也会起作用,但不起作用
            #推荐是因为我们不想硬编码父类。
     

    这里的重要细节是:

    • mixin调用super()。
    • 子类从Mixin first 类Foobar(Foomixin,bar) class。如果基类的顺序是错误的,则永远不会称呼Mixin的构造函数。

  3. 所有基础类都是为合作继承而设计的。

    为合作继承而设计的课程与Mixins很像:它们通过所有未使用的论点将其传递给下一阶级。像以前一样,我们只需要调用super().__ INT __(),所有父构建符都将被链接。

    示例:

     类Coopfoo:
        def __init __(self,** kwargs):
            super().__ init __(** kwargs)#转发所有未使用的论点
            self.foo ='foo'
    
    库班班:
        def __init __(self,bar,** kwargs):
            super().__ init __(** kwargs)#转发所有未使用的论点
            self.bar = bar
    
    Coopfoobar班(Coopfoo,Coopbar):
        def __init __(self,bar ='bar'):
            super().__ init __(bar = bar)#将所有参数作为关键字传递
                                       #避免问题的论点
                                       #位置论点和顺序
                                       父级的#
     

    在这种情况下,父类的顺序无关紧要。我们也可以先从Coopbar首先继承,并且代码仍然可以工作。但这仅此而已,因为所有参数均以关键字参数传递。使用位置参数将使参数的顺序变得容易,因此合作类仅接受关键字参数是习惯的。

    这也是我前面提到的规则的例外:copfoocookbarobject > super().__ init __()。如果没有,就不会有合作的继承。

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

构造函数是班级公共界面的一部分。如果该类被设计为混合蛋白或合作继承,则必须记录在案。如果文档没有提及任何类型的内容,则可以肯定地假设该类不是为合作多重继承而设计的。

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

There are 3 different scenarios:

  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. Example:

    class Foo:
        def __init__(self):
            self.foo = 'foo'
    
    class Bar:
        def __init__(self, bar):
            self.bar = bar
    

    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__(). (Disclaimer: Avoiding super().__init__() in object-subclasses is my personal recommendation and by no means an agreed-upon consensus in the python community. Some people prefer to use super in every class, arguing that you can always write an adapter if the class doesn't behave as you expect.)

    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:

    class Base(object):
        def __init__(self):
            pass
    

    Anyway, in this situation, you will have to call each parent constructor manually. There are two ways to do this:

    • Without super

      class FooBar(Foo, Bar):
          def __init__(self, bar='bar'):
              Foo.__init__(self)  # explicit calls without super
              Bar.__init__(self, bar)
      
    • With super

      class FooBar(Foo, Bar):
          def __init__(self, bar='bar'):
              super().__init__()  # this calls all constructors up to Foo
              super(Foo, self).__init__(bar)  # this calls all constructors after Foo up
                                              # to Bar
      

    Each of these two methods has its own advantages and disadvantages. If you use super, your class will support dependency injection. On the other hand, it's easier to make mistakes. For example if you change the order of Foo and Bar (like class FooBar(Bar, Foo)), you'd have to update the super calls to match. Without super you don't have to worry about this, and the code is much more readable.

  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.

    Example:

    class FooMixin:
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)  # forwards all unused arguments
            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.
    • 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.
  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.

    Example:

    class CoopFoo:
        def __init__(self, **kwargs):
            super().__init__(**kwargs)  # forwards all unused arguments
            self.foo = 'foo'
    
    class CoopBar:
        def __init__(self, bar, **kwargs):
            super().__init__(**kwargs)  # forwards all unused arguments
            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.

    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.

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 cooperative multiple inheritance.

递刀给你 2025-02-08 10:59:39

两种方式都可以正常工作。使用super()的方法可为子类带来更大的灵活性。

在直接呼叫方法中,c .__ Init __可以调用a .__ INT __b .__ INT __ INT __

使用super()时,需要为合作的多重继承而设计,其中c呼叫super,它调用a 的代码也将调用超级调用b的代码。参见 http://rhettinger.wordpress.com/2011/05/26/超级考虑的super 有关super可以完成的操作的更多详细信息。

[以后编辑的回答问题]

所以似乎除非我知道/控制我的阶级的初始
从(a和b)继承我无法为我的班级做出安全的选择
写(c)。

引用的文章通过在ab上添加包装类别来显示如何处理这种情况。标题为“如何合并非合作类”的部分中有一个锻炼示例。

人们可能希望多种继承更容易,让您毫不费力地组合汽车和飞机班来获得飞行车,但是现实是,单独设计的组件通常需要适配器或包装器,然后才能像我们想要的那样无缝地安装在一起

。 :如果您对使用多个继承的功能不满意,则可以使用构图来完全控制哪些情况的方法。

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

In the direct call approach, C.__init__ can call both A.__init__ and 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.

[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).

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".

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 :-)

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.

缱倦旧时光 2025-02-08 10:59:39

如果您控制了ab ,则方法(“新样式”或“旧样式”)将起作用。否则,可能需要使用适配器类。

源代码可访问:此处正确使用“新样式”

class A(object):
    def __init__(self):
        print("-> A")
        super(A, self).__init__()
        print("<- A")

class B(object):
    def __init__(self):
        print("-> B")
        super(B, self).__init__()
        print("<- B")

class C(A, B):
    def __init__(self):
        print("-> C")
        # Use super here, instead of explicit calls to __init__
        super(C, self).__init__()
        print("<- C")
>>> C()
-> C
-> A
-> B
<- B
<- A
<- C

方法解决顺序(mro)以下:

  • c(a,b)首先指示a,然后b。 mro是c - &gt; a - &gt; b - &gt;对象
  • super(a,self)。
  • super(b,self)。

您可以说这种情况是为多个继承而设计的。

源代码可访问:在此处正确使用“旧样式”

class A(object):
    def __init__(self):
        print("-> A")
        print("<- A")

class B(object):
    def __init__(self):
        print("-> B")
        # Don't use super here.
        print("<- B")

class C(A, B):
    def __init__(self):
        print("-> C")
        A.__init__(self)
        B.__init__(self)
        print("<- C")
>>> C()
-> C
-> A
<- A
-> B
<- B
<- C

,MRO并不重要,因为a .__ INT __b .__ INT __ INT __被明确称为。 c(b,a)类:也可以正常工作。

尽管这种情况并不是上一款以新样式的多种继承为“设计”的,但仍然可以使用多个继承。


现在,如果ab来自第三方库 - 即,您无法控制a的源代码和b ?简短的答案:您必须设计一个实现必要super调用的适配器类,然后使用空班来定义MRO(请参阅 raymond hettinger在super 上的文章 - 尤其是“如何合并非合件类”部分” )。

第三方父母:a不实现super; b

class A(object):
    def __init__(self):
        print("-> A")
        print("<- A")

class B(object):
    def __init__(self):
        print("-> B")
        super(B, self).__init__()
        print("<- B")

class Adapter(object):
    def __init__(self):
        print("-> C")
        A.__init__(self)
        super(Adapter, self).__init__()
        print("<- C")

class C(Adapter, B):
    pass
>>> C()
-> C
-> A
<- A
-> B
<- B
<- C

class ADAPTER实施super,以便c可以定义MRO,当> 时会发挥作用超级(适配器,self).__ init __()被执行。

如果相反,该怎么办?

第三方父母:a实现super; b

class A(object):
    def __init__(self):
        print("-> A")
        super(A, self).__init__()
        print("<- A")

class B(object):
    def __init__(self):
        print("-> B")
        print("<- B")

class Adapter(object):
    def __init__(self):
        print("-> C")
        super(Adapter, self).__init__()
        B.__init__(self)
        print("<- C")

class C(Adapter, A):
    pass
>>> C()
-> C
-> A
<- A
-> B
<- B
<- C

在此处不同,除了执行顺序在适配器.__ INIT __中切换。 超级首先致电,然后呼叫。请注意,每个与第三方父母的案例都需要独特的适配器课。

因此,除非我知道/控制我从(ab)继承的类的初始化,否则我无法为i'类的安全选择做出安全的选择。 m写作(<代码> c )。

尽管您可以处理 control ab的源代码的情况,但是您必须知道父母类的初始性如何实现super(如果有的话)才能这样做。

Either approach ("new style" or "old style") will work if you have control over the source code for A and B. Otherwise, use of an adapter class might be necessary.

Source code accessible: Correct use of "new style"

class A(object):
    def __init__(self):
        print("-> A")
        super(A, self).__init__()
        print("<- A")

class B(object):
    def __init__(self):
        print("-> B")
        super(B, self).__init__()
        print("<- B")

class C(A, B):
    def __init__(self):
        print("-> C")
        # Use super here, instead of explicit calls to __init__
        super(C, self).__init__()
        print("<- C")
>>> C()
-> C
-> A
-> B
<- B
<- A
<- C

Here, method resolution order (MRO) dictates the following:

  • C(A, B) dictates A first, then B. MRO is C -> A -> B -> object.
  • super(A, self).__init__() continues along the MRO chain initiated in C.__init__ to B.__init__.
  • super(B, self).__init__() continues along the MRO chain initiated in C.__init__ to object.__init__.

You could say that this case is designed for multiple inheritance.

Source code accessible: Correct use of "old style"

class A(object):
    def __init__(self):
        print("-> A")
        print("<- A")

class B(object):
    def __init__(self):
        print("-> B")
        # Don't use super here.
        print("<- B")

class C(A, B):
    def __init__(self):
        print("-> C")
        A.__init__(self)
        B.__init__(self)
        print("<- C")
>>> C()
-> C
-> A
<- A
-> B
<- B
<- C

Here, MRO does not matter, since A.__init__ and B.__init__ are called explicitly. class C(B, A): would work just as well.

Although this case is not "designed" for multiple inheritance in the new style as the previous one was, multiple inheritance is still possible.


Now, what if A and B are from a third party library - i.e., you have no control over the source code for A and B? The short answer: You must design an adapter class that implements the necessary super calls, then use an empty class to define the MRO (see Raymond Hettinger's article on super - especially the section, "How to Incorporate a Non-cooperative Class").

Third-party parents: A does not implement super; B does

class A(object):
    def __init__(self):
        print("-> A")
        print("<- A")

class B(object):
    def __init__(self):
        print("-> B")
        super(B, self).__init__()
        print("<- B")

class Adapter(object):
    def __init__(self):
        print("-> C")
        A.__init__(self)
        super(Adapter, self).__init__()
        print("<- C")

class C(Adapter, B):
    pass
>>> C()
-> C
-> A
<- A
-> B
<- B
<- C

Class Adapter implements super so that C can define the MRO, which comes into play when super(Adapter, self).__init__() is executed.

And what if it's the other way around?

Third-party parents: A implements super; B does not

class A(object):
    def __init__(self):
        print("-> A")
        super(A, self).__init__()
        print("<- A")

class B(object):
    def __init__(self):
        print("-> B")
        print("<- B")

class Adapter(object):
    def __init__(self):
        print("-> C")
        super(Adapter, self).__init__()
        B.__init__(self)
        print("<- C")

class C(Adapter, A):
    pass
>>> C()
-> C
-> A
<- A
-> B
<- B
<- C

Same pattern here, except the order of execution is switched in Adapter.__init__; super call first, then explicit call. Notice that each case with third-party parents requires a unique adapter class.

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).

Although you can handle the cases where you don't control the source code of A and B by using an adapter class, it is true that you must know how the init's of the parent classes implement super (if at all) in order to do so.

心意如水 2025-02-08 10:59:39

正如雷蒙德(Raymond)在他的回答中所说的那样,直接呼叫a .__ Init __b .__ INT __正常工作,您的代码将是可读的。

但是,它不使用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")

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

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:

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")
心安伴我暖 2025-02-08 10:59:39

如果您是从第三方库乘以子类别类,则不,没有盲目的方法来调用基类__ INT __ INT __方法(或任何其他方法),无论基本类别如何已编程。

super使可能编写旨在合作实现方法的类,作为复杂的多个继承树的一部分,这是班级作者不需要的。但是,没有办法使用它来正确继承可能使用super的任意类。

本质上,无论是使用super还是直接调用基类的班级是属于类的属性,是类“公共接口”的一部分,应将其记录为这样的。如果您以图书馆作者的预期和库具有合理的文档的方式使用第三方库,则通常会告诉您您需要做些什么来为特定的事情。如果不是,那么您必须查看您的子类别的类的源代码,并查看其基础阶级定位约定是什么。如果您以一个或多个第三方库中的多个类的方式组合了库作者没有期望的方式,那么可能不可能始终如一地调用超级级别的方法 根本;如果A类使用super,而B类是不使用Super的层次结构的一部分,那么都不保证任何选项可以正常工作。您必须弄清楚适合每种特定情况的策略。

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.

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.

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.

_蜘蛛 2025-02-08 10:59:39

本文有助于解释合作的多个继承:

或在Python 3中使用Super 3

它提到了有用的方法mro()向您显示方法分辨率订单。在您的第二个示例中,您在a中调用supersuper呼叫继续在 mro 。顺序中的下一个类是b,这就是为什么b的init首次称为INIT的原因。

这是官方Python网站的一篇更具技术性的文章:

python 2.3方法分辨率分辨率顺序

This article helps to explain cooperative multiple inheritance:

The wonders of cooperative inheritance, or using super in Python 3

It mentions the useful method mro() that shows you the method resolution order. In your second 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.

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

The Python 2.3 Method Resolution Order

四叶草在未来唯美盛开 2025-02-08 10:59:39

我添加了一个小型实用库, supers ,这使得这种情况变得更容易处理。它的工作如下:

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")
        supers(self).__init__()
        print("Leaving C")

创建C时输出:输出

Entering C
Entering A
Leaving A
Entering B
Leaving B
Leaving C

I added a small utility library, supers, which makes this kind of scenario simpler to handle. It works as follows:

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")
        supers(self).__init__()
        print("Leaving C")

Output when creating C:

Entering C
Entering A
Leaving A
Entering B
Leaving B
Leaving C
许一世地老天荒 2025-02-08 10:59:39

这是我使用super()在Python&nbsp; 3中实现多个继承的方法

class A:
  def __init__(self, a, b, **kwargs):
      print("Class A initiallised")
      self.a = a
      self.b = b
      super().__init__(**kwargs)
      print("Class A initiallisation done")

  def __str__(self):
      return f"{self.a} and {self.b}"

  def display_a(self):
      return f"{self.a} and {self.b}"

class C:
   def __init__(self, c, d, **kwargs):
      print("Class C initiallised")
      self.c = c
      self.d = d
      super().__init__(**kwargs)
      print("class c initiallisation done")

   def __str__(self):
      return f"{self.c} and {self.d}"

   def display_c(self):
       return f"{self.c} and {self.d}"


class D(A,C):
   def __init__(self, e, **kwargs):
       print("Class D initiallised")
       super().__init__(**kwargs)
       self.e = e
       print("Class D initiallisation done")

   def __str__(self):
      return f"{self.e} is e,{self.b} is b,{self.a} is a,{self.d} is d,{self.c} is c"

if __name__ == "__main__":
   d = D(a=12, b=13, c=14, d=15, e=16)
   print(d)
   d.display_c()
   d.display_a()

Here is how I have implemented the multiple inheritance in Python 3 using super()

class A:
  def __init__(self, a, b, **kwargs):
      print("Class A initiallised")
      self.a = a
      self.b = b
      super().__init__(**kwargs)
      print("Class A initiallisation done")

  def __str__(self):
      return f"{self.a} and {self.b}"

  def display_a(self):
      return f"{self.a} and {self.b}"

class C:
   def __init__(self, c, d, **kwargs):
      print("Class C initiallised")
      self.c = c
      self.d = d
      super().__init__(**kwargs)
      print("class c initiallisation done")

   def __str__(self):
      return f"{self.c} and {self.d}"

   def display_c(self):
       return f"{self.c} and {self.d}"


class D(A,C):
   def __init__(self, e, **kwargs):
       print("Class D initiallised")
       super().__init__(**kwargs)
       self.e = e
       print("Class D initiallisation done")

   def __str__(self):
      return f"{self.e} is e,{self.b} is b,{self.a} is a,{self.d} is d,{self.c} is c"

if __name__ == "__main__":
   d = D(a=12, b=13, c=14, d=15, e=16)
   print(d)
   d.display_c()
   d.display_a()
情魔剑神 2025-02-08 10:59:39

这是我在Python继承中实现超级方法的方式并实现了所需的解决方案:

class A:
    def __init__(self):
        print("from A")

class B:
    def __init__(self):
        print("from B")

class C(A, B):
    def __init__(self):
          A.__init__(self)
          B.__init__(self)
          print("from C")

c = C()

Here is how I have implemented the super method in Python inheritance and achieved the required solution:

class A:
    def __init__(self):
        print("from A")

class B:
    def __init__(self):
        print("from B")

class C(A, B):
    def __init__(self):
          A.__init__(self)
          B.__init__(self)
          print("from C")

c = C()
兮子 2025-02-08 10:59:39
  1. 首先,假设您得到 mro

  2. 链方法,任何使用super()方法的类都会跳入相应的链位置,因为不使用super()方法的任何类都会跳出相应的链位置。

  1. Firstly, suppose you got the MRO chain

  2. From the lowest level subclass init method on, any class which using super() method would jump into corresponding chain position, as any class which not using super() method would jump out corresponding chain position.

沫尐诺 2025-02-08 10:59:39

它遵循 mro rule rule和 ainit

It follows the MRO rule and A init is called.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文