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做什么super().\uuuu init\uuuuuu()和显式超类\uuuuu init\uuuuuu()之间的差异_Python_Oop_Inheritance_Multiple Inheritance_Super - Fatal编程技术网

什么是';超级';你用Python做什么super().\uuuu init\uuuuuu()和显式超类\uuuuu init\uuuuuu()之间的差异

什么是';超级';你用Python做什么super().\uuuu init\uuuuuu()和显式超类\uuuuu init\uuuuuu()之间的差异,python,oop,inheritance,multiple-inheritance,super,Python,Oop,Inheritance,Multiple Inheritance,Super,这两者之间的区别是什么: class Child(SomeBaseClass): def __init__(self): super(Child, self).__init__() 以及: 我见过super在只有单一继承的类中被大量使用。我可以理解为什么要在多重继承中使用它,但不清楚在这种情况下使用它有什么好处。在单一继承中super()的好处是最小的——大多数情况下,您不必将基类的名称硬编码到使用其父方法的每个方法中 但是,如果没有super(),几乎不可能使用多重继

这两者之间的区别是什么:

class Child(SomeBaseClass):
    def __init__(self):
        super(Child, self).__init__()
以及:


我见过
super
在只有单一继承的类中被大量使用。我可以理解为什么要在多重继承中使用它,但不清楚在这种情况下使用它有什么好处。

在单一继承中
super()
的好处是最小的——大多数情况下,您不必将基类的名称硬编码到使用其父方法的每个方法中


但是,如果没有
super()
,几乎不可能使用多重继承。这包括常见的习惯用法,如mixin、接口、抽象类等。这将扩展到以后扩展您的代码。如果后来有人想编写一个扩展了
子类和mixin的类,那么他们的代码将无法正常工作。

所有这些不都假设基类是一个新样式的类吗

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

class B(A):
    def __init__(self):
        print("B.__init__()")
        super(B, self).__init__()
在Python2中不起作用<代码>A类
必须是新型的,即:
A类(对象)

有什么区别? 表示调用
SomeBaseClass
\uuuu init\uuuu
。当

super(Child, self).__init__()
表示从实例的方法解析顺序(MRO)中的
子类之后的父类调用绑定的
\uuuuu init\uuuu

如果该实例是Child的子类,那么在MRO中可能会出现另一个父类

简单解释 当您编写一个类时,您希望其他类能够使用它
super()
使其他类更容易使用您正在编写的类

正如Bob Martin所说,良好的体系结构允许您尽可能长时间地推迟决策

super()
可以启用这种体系结构

当另一个类对您编写的类进行子类化时,它也可以从其他类继承。这些类可以有一个
\uuuuu init\uuuuu
,该
\uuuuuu init\uuuuuu
基于类对方法解析的排序

如果没有
super
,您可能会对正在编写的类的父类进行硬编码(如示例所示)。这意味着您不会在MRO中调用下一个
\uuuu init\uuuu
,因此无法在其中重用代码

如果您正在编写自己的代码供个人使用,那么您可能不关心这种区别。但是,如果您希望其他人使用您的代码,那么使用
super
是允许代码用户具有更大灵活性的一件事

Python 2对3 这在Python 2和Python 3中适用:

super(Child, self).__init__()
这仅适用于Python 3:

super().__init__()
In [26]: D.__mro__
Out[26]: (__main__.D, __main__.B, __main__.C, __main__.A, object)
它通过在堆栈框架中向上移动并获取方法的第一个参数(对于实例方法通常是
self
,对于类方法通常是
cls
,但是可以是其他名称)并在自由变量中查找类(例如
Child
)(在方法中以名称
\uuuuu class\uuuu
作为自由闭包变量进行查找)

我更愿意演示使用
super
的交叉兼容方式,但如果您只使用Python 3,则可以不带参数地调用它

具有前向兼容性的间接寻址 它给了你什么?对于单一继承,从静态分析的角度来看,问题中的示例实际上是相同的。但是,使用
super
给了你一层具有前向兼容性的间接层

前向兼容性对于经验丰富的开发人员来说非常重要。您希望代码在更改时保持最小的更改。当您查看修订历史时,您希望准确地看到更改的内容

您可以从单一继承开始,但是如果您决定添加另一个基类,您只需要更改基类的行-如果您继承的类中的基类发生了更改(例如添加了mixin)在这个类中,您不会做任何更改。尤其是在Python 2中,获得
super
的参数和正确的方法参数可能会很困难。如果您知道您在单继承中正确使用了
super
,这将降低调试的难度

依赖注入 其他人可以使用您的代码并将父项注入到方法解析中:

class SomeBaseClass(object):
    def __init__(self):
        print('SomeBaseClass.__init__(self) called')

class UnsuperChild(SomeBaseClass):
    def __init__(self):
        print('UnsuperChild.__init__(self) called')
        SomeBaseClass.__init__(self)

class SuperChild(SomeBaseClass):
    def __init__(self):
        print('SuperChild.__init__(self) called')
        super(SuperChild, self).__init__()
假设您向对象添加了另一个类,并希望在Foo和Bar之间插入一个类(出于测试或其他原因):

使用un super子级无法注入依赖项,因为您正在使用的子级已硬编码要在其自己的子级之后调用的方法:

>>> o = UnsuperInjector()
UnsuperChild.__init__(self) called
SomeBaseClass.__init__(self) called
但是,使用
super
的子类可以正确地注入依赖项:

>>> o2 = SuperInjector()
SuperChild.__init__(self) called
InjectMe.__init__(self) called
SomeBaseClass.__init__(self) called
发表评论 这到底为什么有用呢

Python通过将复杂的继承树线性化来创建方法解析顺序(MRO)

我们希望按照这个顺序查找方法

对于在父级中定义的方法,如果不使用
super
,则必须按该顺序查找下一个方法

  • 从实例的类型获取mro
  • 查找定义该方法的类型
  • 使用该方法查找下一个类型
  • 绑定该方法并使用预期参数调用它
  • unperspechild
    不应该访问
    InjectMe
    。为什么结论不是“总是避免使用
    super
    ”?我在这里遗漏了什么

    unperhild
    无权访问
    InjectMe
    。只有
    unperhilder
    才有权访问
    InjectMe
    ,但无法从继承自
    unperhild
    的方法调用该类的方法

    两个子类都打算用MRO中接下来出现的相同名称调用一个方法,这可能是它在创建时不知道的另一个类

    没有
    super
    硬编码其父方法的方法-因此
    >>> o = UnsuperInjector()
    UnsuperChild.__init__(self) called
    SomeBaseClass.__init__(self) called
    
    >>> o2 = SuperInjector()
    SuperChild.__init__(self) called
    InjectMe.__init__(self) called
    SomeBaseClass.__init__(self) called
    
    super(B, b) 
    # resolves to the scope of B's parent i.e. A 
    # and applies that scope to b, as if b was an instance of A
    
    super(C, c) 
    # resolves to the scope of C's parent i.e. B
    # and applies that scope to c
    
    super(B, c) 
    # resolves to the scope of B's parent i.e. A 
    # and applies that scope to c
    
    class A(object):
        def __new__(cls, *a, **kw):
            # ...
            # whatever you want to specialize or override here
            # ...
    
            return super(A, cls).__new__(cls, *a, **kw)
    
    # if you defined this
    class A(object):
        def __new__(cls):
            pass
    
    # calling this would raise a TypeError due to the missing argument
    A.__new__()
    
    # whereas this would be fine
    A.__new__(A)
    
    super(A, cls)
    
    super(A, cls).__new__(cls, *a, **kw)
    
    class A(object):
        def __new__(cls, *a, **kw):
            # ...
            # whatever you want to specialize or override here
            # ...
    
            return object.__new__(cls, *a, **kw)
    
    class A(object): 
        def __init__(self, *a, **kw):
            # ...
            # you make some changes here
            # ...
    
            super(A, self).__init__(*a, **kw)
    
    # you try calling `__init__()` from the class without specifying an instance
    # and a TypeError is raised due to the expected but missing reference
    A.__init__() # TypeError ...
    
    # you create an instance
    a = A()
    
    # you call `__init__()` from that instance and it works
    a.__init__()
    
    # you can also call `__init__()` with the class and explicitly pass the instance 
    A.__init__(a)
    
    super(A, self)
    
    class A(object): 
        def __init__(self, *a, **kw):
            # ...
            # you make some changes here
            # ...
    
            object.__init__(self, *a, **kw)
    
    class A(object):
        @classmethod
        def alternate_constructor(cls, *a, **kw):
            print "A.alternate_constructor called"
            return cls(*a, **kw)
    
    class B(A):
        @classmethod
        def alternate_constructor(cls, *a, **kw):
            # ...
            # whatever you want to specialize or override here
            # ...
    
            print "B.alternate_constructor called"
            return super(B, cls).alternate_constructor(*a, **kw)
    
    # calling directly from the class is fine,
    # a reference to the class is passed implicitly
    a = A.alternate_constructor()
    b = B.alternate_constructor()
    
    super(B, cls_or_subcls)
    
    super(B, cls).alternate_constructor()
    
    class B(A):
        @classmethod
        def alternate_constructor(cls, *a, **kw):
            # ...
            # whatever you want to specialize or override here
            # ...
    
            print "B.alternate_constructor called"
            return A.alternate_constructor(cls, *a, **kw)
    
    class B(A):
        @classmethod
        def alternate_constructor(cls, *a, **kw):
            # ...
            # whatever you want to specialize or override here
            # ...
    
            print "B.alternate_constructor called"
            # first we get a reference to the unbound 
            # `A.alternate_constructor` function 
            unbound_func = A.alternate_constructor.im_func
            # now we call it and pass our own `cls` as its first argument
            return unbound_func(cls, *a, **kw)
    
        A
       / \
      B   C
       \ /
        D
    
    In [26]: D.__mro__
    Out[26]: (__main__.D, __main__.B, __main__.C, __main__.A, object)
    
    In [23]: class A(object): #  or with Python 3 can define class A:
    ...:     def __init__(self):
    ...:         print("I'm from A")
    ...:  
    ...: class B(A):
    ...:      def __init__(self):
    ...:          print("I'm from B")
    ...:          super().__init__()
    ...:   
    ...: class C(A):
    ...:      def __init__(self):
    ...:          print("I'm from C")
    ...:          super().__init__()
    ...:  
    ...: class D(B, C):
    ...:      def __init__(self):
    ...:          print("I'm from D")
    ...:          super().__init__()
    ...: d = D()
    ...:
    I'm from D
    I'm from B
    I'm from C
    I'm from A
    
        A
       / ⇖
      B ⇒ C
       ⇖ /
        D
    
    In [21]: class A(object):  # or class A:
    ...:     def __init__(self):
    ...:         print("I'm from A")
    ...:  
    ...: class B(A):
    ...:      def __init__(self):
    ...:          super().__init__()  # or super(B, self).__init_()
    ...:          print("I'm from B")
    ...:   
    ...: class C(A):
    ...:      def __init__(self):
    ...:          super().__init__()
    ...:          print("I'm from C")
    ...:  
    ...: class D(B, C):
    ...:      def __init__(self):
    ...:          super().__init__()
    ...:          print("I'm from D")
    ...: d = D()
    ...: 
    I'm from A
    I'm from C
    I'm from B
    I'm from D
    
        A
       / ⇘
      B ⇐ C
       ⇘ /
        D 
    
    class Child(SomeBaseClass):
        def __init__(self):
            SomeBaseClass.__init__(self)
    
    class Child(SomeBaseClass):
        def __init__(self):
            super(Child, self).__init__()
    
    E name=python age=28
    C age=28
    A
    D name=python
    B
    SuperObject
    
    Class Jen(Cain, Sue):
    
    X
    Y
    Q
    
    X
    P
    Y
    Q
    
    class Base(object):
        def __init__(self):
            print("initializing Base")
    
    class ChildA(Base):
        def __init__(self):
            print("initializing ChildA")
            Base.__init__(self)
    
    class ChildB(Base):
        def __init__(self):
            print("initializing ChildB")
            super().__init__()
    
    class Grandchild(ChildA, ChildB):
        def __init__(self):
            print("initializing Grandchild")
            super().__init__()
            
    Grandchild()
    
    initializing Grandchild
    initializing ChildA
    initializing Base
    
    initializing Grandchild
    initializing ChildA
    initializing ChildB
    initializing Base
    
    class A:
        def m(self):
            print('A')
    
    class B(A):
        def m(self):
            print('B start')
            super().m()
            print('B end')
            
    class C(A):
        def m(self):
            print('C start')
            super().m()
            print('C end')
    
    class D(B, C):
        def m(self):
            print('D start')
            super().m()
            print('D end')
    
    >>> a = A()
    >>> b = B()
    >>> c = C()
    >>> d = D()
    
    >>> a.m()
    A
    
    >>> type(b).__mro__   
    (<class '__main__.B'>, <class '__main__.A'>, <class 'object'>)
    
    >>> b.m()
    B start
    A
    B end
    
    >>> type(c).__mro__   
    (<class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
    
    >>> b.m()
    C start
    A
    C end
    
    >>> type(d).__mro__
    (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
    
    >>> d.m()
    D start
    B start
    C start
    A
    C end
    B end
    D end