Расширение 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 73

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())