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

时间:2012-05-07 13:28:42

标签: python inheritance configparser

最初我想问this question,但后来我发现它已经被考虑过了......

在谷歌上搜索我发现extending 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和Old Class样式(例如here)。 现在我想知道,我能做到:

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)

5 个答案:

答案 0 :(得分:134)

    在Python 3中引入了
  • super()(不带参数)(以及__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)
    

答案 1 :(得分:42)

在单个继承的情况下(当你只为一个类创建子类时),新类继承了基类的方法。这包括__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中的下一个类调用方法(方法解析顺序)。 C的MRO是:(C, A, B, object)。您可以打印C.__mro__进行查看。

因此,C继承__init__中的Asuper来电A.__init__ B.__init__ B A C在MRO)。

所以,在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)

__init__

问题在于,在更复杂的MI树中,某些类的{{1}}方法可能不止一次被调用,而super / MRO保证它们只被调用一次。

答案 2 :(得分:22)

简而言之,它们是等同的。 我们有一个历史视图:

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

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

(2)使代码更抽象(更便携)。获得Super-Class的常用方法是:

    super(<class>, <instance>)

init函数可以是:

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

然而,要求显式传递类和实例会破坏DRY(不要重复自己)规则。

V3中的(3)。它更聪明,

    super()
在大多数情况下,

就足够了。您可以参考http://www.python.org/dev/peps/pep-3135/

答案 3 :(得分:19)

只是为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

答案 4 :(得分:1)

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

  

super()。初始化(名称,10)

具有相同的效果
  

人员。初始化(自己,姓名,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())