问题:Python扩展-使用super()Python 3 vs Python 2
本来我想问这个问题,但是后来我发现它已经被想到了……
在谷歌搜索中发现了扩展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)
回答 0
回答 1
在单个继承的情况下(仅当子类化一个类时),新类将继承基类的方法。这包括__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__
自调用A
并super
在A.__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保证只将它们调用一次。
回答 2
简而言之,它们是等效的。让我们来看看历史:
(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/
回答 3
只是为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
另一个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())