Python扩展-使用super()Python 3 vs Python 2


103

本来我想问这个问题,但是后来我发现它已经被想到了……

在谷歌搜索中发现了扩展configparser的示例。以下适用于Python 3:

$ python3
Python 3.2.3rc2 (default, Mar 21 2012, 06:59:51) 
[GCC 4.6.3] on linux2
>>> from configparser import  SafeConfigParser
>>> class AmritaConfigParser(SafeConfigParser):
...     def __init_(self):
...         super().__init__()
... 
>>> cfg = AmritaConfigParser()

但不适用于Python 2:

>>> class AmritaConfigParser(SafeConfigParser):
...       def __init__(self):
...           super(SafeConfigParser).init()
... 
>>> cfg = AmritaConfigParser()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in __init__
TypeError: must be type, not classob

然后,我读了一些关于Python New Class vs. Old Class样式的信息(例如,在这里。现在我想知道,我可以这样做:

class MyConfigParser(ConfigParser.ConfigParser):
      def Write(self, fp):
          """override the module's original write funcition"""
          ....
      def MyWrite(self, fp):
          """Define new function and inherit all others"""

但是,我不应该叫init吗?这在Python 2中是否等效:

 class AmritaConfigParser(ConfigParser.SafeConfigParser):
    #def __init__(self):
    #    super().__init__() # Python3 syntax, or rather, new style class syntax ...
    #
    # is this the equivalent of the above ? 
    def __init__(self):
        ConfigParser.SafeConfigParser.__init__(self)

1
在您的示例__init__()中,如果只需要调用超类__init__()(在Python 2或3中),则无需在子类中定义一个-而是让超类被继承。
martineau 2013年

有用的参考资料:amyboyle.ninja/Python-Inheritance
nu

正确的链接的有用参考:amyboyle.ninja/Python-Inheritance
fearless_fool

Answers:


155
  • super()(不带参数)在Python 3中(以及__class__)引入:

    super() -> same as super(__class__, self)

    这样就相当于新样式类的Python 2:

    super(CurrentClass, self)
  • 对于老式类,您可以始终使用:

     class Classname(OldStyleParent):
        def __init__(self, *args, **kwargs):
            OldStyleParent.__init__(self, *args, **kwargs)

8
-1。这个答案并没有为我澄清任何事情。在Python 2中,super(__class__)given NameError: global name '__class__' is not definedsuper(self.__class__)也是错误的。您必须提供一个实例作为第二个参数,这表明您需要这样做super(self.__class__, self),但这是错误的。如果Class2从继承Class1Class1电话super(self.__class__, self).__init__()Class1__init__会再调用自身实例的实例时Class2
jpmc26

为了阐明一点,我TypeError: super() takes at least 1 argument (0 given)在尝试使用super(self.__class__)Python 2 进行调用时会明白这一点。(这没有多大意义,但它表明此答案中缺少多少信息。)
jpmc26 2015年

3
@ jpmc26:在python2你,因为你想打电话得到这个错误__init__()没有绑定超级对象(通过调用得到的说法super(self.__class__)只有一个参数),您需要绑定超级对象,然后它应该工作:super(CurrentClass, self).__init__()。不要使用,self.__class__因为在调用父对象时它将始终引用同一个类,因此如果该父对象也执行相同的操作,则会创建一个无限循环。
马塔

__class__(成员)也存在于Python2中
CristiFati

3
@CristiFati这与__class__成员无关,而是与隐式创建的词法__class__闭包有关,后者始终引用当前正在定义的类,而python2中不存在该类。
马塔

48

在单个继承的情况下(仅当子类化一个类时),新类将继承基类的方法。这包括__init__。因此,如果您不在课堂上定义它,那么您将从基础中获得一个。

如果引入多重继承(一次子类化多个类),事情就会变得复杂起来。这是因为如果有多个基类__init__,则您的类将仅继承第一个基类。

在这种情况下,super如果可以的话,您应该真正使用,我会解释原因。但并非总是可以。问题是您所有的基类也必须使用它(以及它们的基类-整个树)。

如果是这种情况,那么这也将正常工作(在Python 3中,但您可以将其重新制作为Python 2-它还具有super):

class A:
    def __init__(self):
        print('A')
        super().__init__()

class B:
    def __init__(self):
        print('B')
        super().__init__()

class C(A, B):
    pass

C()
#prints:
#A
#B

请注意,super即使它们没有自己的基类,这两个基类也如何使用。

什么super做的是:它要求从隔壁班的MRO方法(方法解析顺序)。的MRO为C(C, A, B, object)。您可以打印C.__mro__以查看它。

因此,C继承__init__自调用AsuperA.__init__调用中继承B.__init__(在MRO中B遵循A)。

因此,通过不执行任何操作C,最终会同时调用这两者,而这正是您想要的。

现在,如果您不使用super,您将最终继承A.__init__(与以前一样),但是这次没有什么B.__init__需要您使用。

class A:
    def __init__(self):
        print('A')

class B:
    def __init__(self):
        print('B')

class C(A, B):
    pass

C()
#prints:
#A

要解决此问题,您必须定义C.__init__

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

这样做的问题是,在更复杂的MI树中,__init__某些类的方法最终可能会被多次调用,而super / MRO保证只将它们调用一次。


10
Notice how both base classes use super even though they don't have their own base classes.他们有。在py3k中,每个类都子类化对象。
akaRem'5

这是我一直在寻找的答案,但不知道如何问。MRO描述很好。
dturvene

27

简而言之,它们是等效的。让我们来看看历史:

(1)首先,函数看起来像这样。

    class MySubClass(MySuperClass):
        def __init__(self):
            MySuperClass.__init__(self)

(2)使代码更抽象(更便于移植)。发明超类的一种常见方法是:

    super(<class>, <instance>)

初始化函数可以是:

    class MySubClassBetter(MySuperClass):
        def __init__(self):
            super(MySubClassBetter, self).__init__()

但是,要求显式传递类和实例都违反了DRY(请勿重复自己)规则。

(3)在V3中。更聪明

    super()

在大多数情况下就足够了。您可以参考http://www.python.org/dev/peps/pep-3135/


22

只是为Python 3提供一个简单而完整的示例,大多数人似乎正在使用它。

class MySuper(object):
    def __init__(self,a):
        self.a = a

class MySub(MySuper):
    def __init__(self,a,b):
        self.b = b
        super().__init__(a)

my_sub = MySub(42,'chickenman')
print(my_sub.a)
print(my_sub.b)

42
chickenman

3

另一个python3实现,其中涉及将Abstract类与super()结合使用。你应该记住

super().__init__(name, 10)

与...具有相同的效果

Person.__init__(self, name, 10)

请记住,super()中有一个隐藏的“自我”,因此同一对象会传递给超类init方法,并且属性会添加到调用它的对象中。因此super()被翻译为 Person,然后如果您包含隐藏的自身,则会得到上面的代码片段。

from abc import ABCMeta, abstractmethod
class Person(metaclass=ABCMeta):
    name = ""
    age = 0

    def __init__(self, personName, personAge):
        self.name = personName
        self.age = personAge

    @abstractmethod
    def showName(self):
        pass

    @abstractmethod
    def showAge(self):
        pass


class Man(Person):

    def __init__(self, name, height):
        self.height = height
        # Person.__init__(self, name, 10)
        super().__init__(name, 10)  # same as Person.__init__(self, name, 10)
        # basically used to call the superclass init . This is used incase you want to call subclass init
        # and then also call superclass's init.
        # Since there's a hidden self in the super's parameters, when it's is called,
        # the superclasses attributes are a part of the same object that was sent out in the super() method

    def showIdentity(self):
        return self.name, self.age, self.height

    def showName(self):
        pass

    def showAge(self):
        pass


a = Man("piyush", "179")
print(a.showIdentity())
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.