Python, расширяющийся с использованием супер() Python 3 vs Python 2
Изначально я хотел задать этот вопрос, но потом я обнаружил, что это уже было сказано раньше...
Включение googling я нашел этот пример расширения 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 (например здесь.
И теперь мне интересно, я могу сделать:
class MyConfigParser(ConfigParser.ConfigParser):
def Write(self, fp):
"""override the module 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
-
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)
Ответ 2
В одном случае наследования (при подклассе только одного класса) ваш новый класс наследует методы базового класса. Это включает __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__
(B
следует за A
в MRO).
Итак, ничего не делая в 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 гарантируют, что они вызываются только один раз.
Ответ 3
Короче говоря, они эквивалентны.
Пусть имеет вид истории:
(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 (Do not Repeat Yourself).
(3) в V3. Это более умный,
super()
достаточно в большинстве случаев. Вы можете обратиться к http://www.python.org/dev/peps/pep-3135/
Ответ 4
Просто, чтобы иметь простой и полный пример для 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