使用 super() Python 3与 Python 2进行 Python 扩展

原本我想问 这个问题,但后来我发现它已经想到之前..。

我在谷歌上找到了这个 扩展配置解析器扩展配置解析器的例子:

$ 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 新类与旧类样式(例如 给你)的内容。 现在我想知道,我能做的是:

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

 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)
170939 次浏览

在单个继承情况下(当您只继承一个类时) ,您的新类继承基类的方法。这包括 __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__来查看它。

因此,CA继承 __init__,在 A.__init__调用 B.__init__时继承 super(B在 MRO 中跟随 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 保证它们只被调用一次。

  • super() (没有参数)是在 Python 3(与 __class__一起)中引入的:

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

    因此,对于新样式的类来说,这将是 Python 2的等价物:

    super(CurrentClass, self)
    
  • for old-style classes you can always use:

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

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

(1)起初,函数是这样的。

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

(2)使代码更抽象(和更便携)。获得超级类的一个常见方法是这样发明的:

    super(<class>, <instance>)

Init 函数可以是:

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

但是,如果需要显式传递类和实例,则稍微违反了 DRY (Don’t Repeat Yourself)规则。

(3)在 V3。它更聪明,

    super()

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

只是为了有一个简单而完整的 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

另一个 python3实现涉及使用具有 super ()的抽象类

super().__init__(name, 10)

和... 有同样的效果

Person.__init__(self, name, 10)

记住 super ()中有一个隐藏的“ self”,所以相同的对象传递给超类 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())