Вопрос по python, inheritance – Python расширяется с использованием super () Python 3 против Python 2

83

Изначально я хотел спроситьэтот вопрос, но потом я обнаружил, что об этом уже думали раньше ...

Погуглив, я нашел этот примеррасширяющий configparser, Следующие работы с Python 3:

<code>$ 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()
</code>

Но не с Python 2:

<code>>>> 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
</code>

Затем я немного прочитал о стилях Python New Class и Old Class (например,Вот. And now I am wondering, I can do:

<code>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"""
</code>

Но разве я не должен вызывать init? Это в Python 2 эквивалентно:

<code> 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)
</code>
Полезная ссылка:amyboyle.ninja/Python-Inheritance nu everest
Полезная ссылка с исправленной ссылкой:amyboyle.ninja/Python-Inheritance fearless_fool
В вашем примере вам не нужно определять__init__() в подклассе, если все, что он делает, это вызывает суперкласс & apos;__init__() (либо в Python 2, либо в 3) - вместо этого просто позвольте супер наследоваться. martineau

Ваш Ответ

5   ответов
40

В одном случае наследования (когда вы создаете подкласс только для одного класса), ваш новый класс наследует методы базового класса. Это включает__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 do is: вызывает метод из следующего класса в MRO (порядок разрешения методов). MRO дляC является:(C, A, B, object), Вы можете распечататьC.__mro__ чтобы увидеть это.

Так,C наследуется__init__ отA а такжеsuper вA.__init__ звонкиB.__init__ (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 гарантирует, что они были вызваны только один раз.

Notice how both base classes use super even though they don't have their own base classes. У них есть. В py3k каждый класс подклассов объекта.
132
  • super() (without arguments) was introduced in Python 3 (along with __class__):

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

    so that would be the Python 2 equivalent for new-style classes:

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

     class Classname(OldStyleParent):
        def __init__(self, *args, **kwargs):
            OldStyleParent.__init__(self, *args, **kwargs)
    
__class__ (член) также существует вPython2.
Чтобы уточнить точку, я получаюTypeError: super() takes at least 1 argument (0 given) при попытке позвонитьsuper(self.__class__) в Python 2. (Что не имеет большого смысла, но показывает, сколько информации не хватает в этом ответе.)
@CristiFati Это не о__class__ член, но оimplicitly created lexical __class__ closure который всегда ссылается на класс, который в настоящее время определяется, который не существует в python2.
-1. Этот ответ ничего не прояснил для меня. В Python 2super(__class__) даетNameError: global name '__class__' is not defined, а такжеsuper(self.__class__) также ошибочен. Выmust предоставить экземпляр в качестве второго аргумента, который предполагает, что вам нужно сделатьsuper(self.__class__, self)но этоwrong, ЕслиClass2 наследует отClass1 а такжеClass1 звонкиsuper(self.__class__, self).__init__(), Class1& APOS; s__init__ будет затемcall itself при создании экземпляраClass2.
@ jpmc26: в python2 вы получаете эту ошибку, потому что вы пытаетесь позвонить__init__() без аргумента о несвязанном суперобъекте (который вы получите, вызвавsuper(self.__class__) только с одним аргументом), вам нужен связанный суперобъект, тогда он должен работать:super(CurrentClass, self).__init__(), Не используйтеself.__class__ потому что это всегда будет относиться кsame Класс при вызове родителя и, следовательно, создает бесконечный цикл, если этот родитель также делает то же самое.
22

Короче говоря, они эквивалентны. Давайте рассмотрим историю:

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

Однако, требуя явной передачи как класса, так и экземпляра, немного нарушите правило СУХОГО (не повторяйте себя).

(3) в V3. Это умнее,

    super()

достаточно в большинстве случаев. Вы можете обратиться кhttp://www.python.org/dev/peps/pep-3135/

0

Еще одна реализация python3, которая включает использование абстрактных классов с 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())
14

Просто иметь простой и полный пример для 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

Похожие вопросы