Расширение 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 новый класс против старых стилей класса (например,здесь. И теперь мне интересно, я могу сделать:
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 ответов:
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)
в одном случае наследования (когда вы подкласс только один класс), ваш новый класс наследует методы базового класса. Это включает в себя
__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
does is: он вызывает метод из следующего класса в 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 гарантируют, что они будут вызваны только один раз.
короче говоря, они эквивалентны. Давайте посмотрим историю:
(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 (не повторяйте себя).
(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(наименование, 10)
аналогично
человек.init(self, name, 10)
помните, что в super () есть скрытое "я", поэтому тот же объект переходит к методу инициализации суперкласса, и атрибуты добавляются к объекту, который называть это. Отсюда
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())