Почему Python super используется в методе init ребенка? - PullRequest
2 голосов
/ 12 апреля 2020

Согласно Python документам super ()

полезно для доступа к унаследованным методам, которые были переопределены в классе.

Я понимаю, что super относится к родительскому классу и позволяет вам получить доступ к родительским методам. Мой вопрос: почему люди всегда используют super внутри метода init дочернего класса? Я видел это везде. Например:

class Person:

    def __init__(self, name):
        self.name = name

class Employee(Person):
    def __init__(self, **kwargs):
       super().__init__(name=kwargs['name']) # Here super is being used

    def first_letter(self):
        return self.name[0]

e = Employee(name="John")
print(e.first_letter())

Я могу выполнить sh то же самое без супер и даже без init метода:

class Person:

    def __init__(self, name):
        self.name = name

class Employee(Person):

    def first_letter(self):
        return self.name[0]

e = Employee(name="John")
print(e.first_letter())

Есть ли недостатки у последнего код? Это выглядит намного чище для меня. Мне даже не нужно использовать шаблонный ** kwargs и kwargs ['аргумент'] синтаксис.

Я использую Python 3.8. Редактировать: Вот вопросы nother stackoverflow , в которых есть код от разных людей, которые используют super в методе init ребенка. Я не понимаю почему. По-моему, в Python 3.8.

есть что-то новое.

Ответы [ 3 ]

3 голосов
/ 12 апреля 2020

Ребенок может захотеть сделать что-то другое или, что более вероятно, в дополнение к тому, что делает суперкласс - в этом случае у ребенка должен быть __init__.

Вызов init init супер означает, что вам не нужно копировать / вставлять (со всеми последствиями для обслуживания), что init в дочернем классе, что в противном случае понадобилось бы, если бы вы хотели некоторый дополнительный код в дочернем init .

Но учтите, что использование init-суперпользователя сопряжено с трудностями, если вы используете множественное наследование (например, какой супер-вызов вызывается), и это требует осторожности. Лично я избегаю множественного наследования и в любом случае сохраняю наследование минимальным - легко соблазниться на создание нескольких уровней иерархии наследования / классов, но мой опыт заключается в том, что подход «будь проще» обычно намного лучше.

1 голос
/ 12 апреля 2020

Потенциальным недостатком последнего кода является отсутствие метода __init__ в классе Employee. Поскольку его нет, вызывается метод __init__ родительского класса. Однако, как только метод __init__ добавляется в класс Employee (может быть, есть некоторый атрибут Employee-Speci c, который необходимо инициализировать, например, id_number), метод __init__ родительского класса переопределяется и не вызывается (если не вызывается super.__init__()), и тогда у сотрудника не будет атрибута name.

1 голос
/ 12 апреля 2020

Правильный способ использования super здесь для обоих методов для использования super. Вы не можете предполагать, что Person является последним (или, по крайней мере, ближайшим к последнему, перед object) классом в MRO.

class Person:

    def __init__(self, name, **kwargs):
        super().__init__(**kwargs)
        self.name = name

class Employee(Person):
    # Optional, since Employee.__init__ does nothing
    # except pass the exact same arguments "upstream"
    def __init__(self, **kwargs):
       super().__init__(**kwargs)

    def first_letter(self):
        return self.name[0]

Рассмотрите определение класса, подобное

class Bar:
    ...

class Foo(Person, Bar):
    ...

MRO для Foo выглядит как [Foo, Person, Bar, object]; вызов super().__init__ внутри Person.__init__ вызовет Bar.__init__, а не object.__init__, и Person не сможет узнать, предназначены ли значения в **kwargs для Bar, поэтому должен передать их.

...