Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 调用具有多重继承的父类uu init uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu;这条路对吗?_Python_Oop_Inheritance_Multiple Inheritance_Super - Fatal编程技术网

Python 调用具有多重继承的父类uu init uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu;这条路对吗?

Python 调用具有多重继承的父类uu init uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu;这条路对吗?,python,oop,inheritance,multiple-inheritance,super,Python,Oop,Inheritance,Multiple Inheritance,Super,假设我有一个多重继承场景: 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? 编写C的\uuuu i

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

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?
编写
C
\uuuu init\uuu
有两种典型的方法:

  • (旧式)
    ParentClass.\uuuu init\uuuu(self)
  • (较新的样式)
    super(DerivedClass,self)。\uuu init\uuuu()
  • 但是,在这两种情况下,如果父类(
    A
    B
    )(有些可能会丢失,或者被多次调用)

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

    编辑:要了解我的意思,如果我这样做:

    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永远不会被调用。因此,除非我知道/控制我从中继承的类(
    A
    B
    )的初始值,否则我无法为我正在编写的类(
    C
    )做出安全的选择。

    这两种方法都可以很好地工作。使用
    super()
    的方法为子类带来了更大的灵活性

    在直接调用方法中,
    C.\uuu init\uu
    可以调用
    A.\uu init\uuu
    B.\uu init\uu

    当使用
    super()
    时,类需要设计为协同多重继承,其中
    C
    调用
    super
    ,调用
    A
    的代码,后者也将调用
    super
    ,后者调用
    B
    的代码。有关如何使用
    super
    的更多详细信息,请参阅

    [回答问题,稍后编辑]

    因此,除非我知道/控制类的init,否则 继承自(A和B)我不能为我所属的类做出安全的选择 写作(C)

    参考文章展示了如何通过在
    a
    B
    周围添加包装类来处理这种情况。在题为“如何合并非合作类”的章节中有一个已制定的示例

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


    另一个想法是:如果您对使用多重继承组合功能不满意,您可以使用组合来完全控制在哪些情况下调用哪些方法。

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

    在直接调用方法中,
    C.\uuu init\uu
    可以调用
    A.\uu init\uuu
    B.\uu init\uu

    当使用
    super()
    时,类需要设计为协同多重继承,其中
    C
    调用
    super
    ,调用
    A
    的代码,后者也将调用
    super
    ,后者调用
    B
    的代码。有关如何使用
    super
    的更多详细信息,请参阅

    [回答问题,稍后编辑]

    因此,除非我知道/控制类的init,否则 继承自(A和B)我不能为我所属的类做出安全的选择 写作(C)

    参考文章展示了如何通过在
    a
    B
    周围添加包装类来处理这种情况。在题为“如何合并非合作类”的章节中有一个已制定的示例

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


    另一个想法是:如果您不喜欢使用多重继承组合功能,您可以使用组合来完全控制在哪些情况下调用哪些方法。

    如果您要从第三方库中复制子类,则不,调用基类
    \uuuu init\uuuu
    方法(或任何其他方法)时没有盲目的方法,而不管基类是如何编程的

    super
    使编写类成为可能,这些类的设计目的是作为复杂多重继承树的一部分协同实现方法,而类作者不需要知道这些树。但无法使用它正确继承可能使用或可能不使用
    super
    的任意类


    本质上,一个类是否被设计成使用
    super
    或直接调用基类的子类是一个属性,它是该类“公共接口”的一部分,并且应该这样记录。如果您以库作者期望的方式使用第三方库,并且该库有合理的文档,它通常会告诉您需要做什么来对特定事物进行子类化。如果没有,那么您必须查看正在子分类的类的源代码,并查看它们的基类调用约定是什么。如果您以库作者没有预料到的方式组合来自一个或多个第三方库的多个类,那么可能根本不可能一致地调用超类方法;如果类A是使用
    super
    的层次结构的一部分,而类B是不使用super的层次结构的一部分,则两个选项都不能保证有效。您必须找出一种适合于每种特定情况的策略。

    如果您要从第三方库中倍增子类,那么不,调用基类
    \uuuuuu init\uuuu
    方法(或任何其他方法)没有盲目的方法
    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")
    
    class Foo:
        def __init__(self):
            self.foo = 'foo'
    
    class Bar:
        def __init__(self, bar):
            self.bar = bar
    
    class Base(object):
        def __init__(self):
            pass
    
    class FooBar(Foo, Bar):
        def __init__(self, bar='bar'):
            Foo.__init__(self)  # explicit calls without super
            Bar.__init__(self, bar)
    
    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
    
    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.
    
    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
    
    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
    
    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
    
    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 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
    
    Entering C
    Entering A
    Leaving A
    Entering B
    Leaving B
    Leaving C
    
    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()