От новичка до гуру: Курсы программирования на CyberDuff

Почему Python super используется в дочернем методе инициализации?

Согласно документам 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())

Я могу сделать то же самое без super и даже без метода 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['argument'].

Я использую Python 3.8. Изменить: вот другой вопрос о переполнении стека, в котором есть код от разных людей, которые используют super в дочернем методе инициализации. Я не понимаю, почему. Я думаю, что в Python 3.8 появилось что-то новое.


  • Если вы не определите init в дочернем классе, он будет унаследован от родительского класса. 12.04.2020
  • В данном случае он вам особо не нужен. Единственная разница между этой реализацией и тем, что Employee.__init__ разрешается в Person.__init__, состоит в том, что kwargs['name'] может вызвать KeyError. 12.04.2020
  • На самом деле это еще хуже; он отбрасывает аргументы, которые могут понадобиться классу в MRO, о котором Person не знает. Оба Person.__init__ и Child.__init__ должны вызывать super().__init__ с помощью **kwargs. 12.04.2020
  • Родительский класс также может состоять из гораздо большего, чем просто присвоение свойства (как в вашем примере). 12.04.2020

Ответы:


1

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

12.04.2020

2

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

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

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

12.04.2020
  • Когда вы говорите, что ребенок может захотеть сделать что-то другое или дополнительное к тому, что делает суперкласс, что именно вы имеете в виду под чем-то? Можете ли вы привести пример или два? 12.04.2020
  • Например. у дочернего элемента есть дополнительный атрибут, который необходимо инициализировать. 12.04.2020

  • 3

    Здесь правильно использовать 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, поэтому он должен передавать их дальше.

    12.04.2020
    Новые материалы

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

    Представляем Narwhal Technologies (Nrwl)
    6 декабря 2016 г. Маунтин-Вью, Калифорния С тех пор, как Виктор Савкин и я (Джефф Кросс) присоединились к команде Angular в Google на заре Angular 1, Angular продемонстрировал феноменальный..

    Путь AWS  — «Изучение машинного обучения — 10 начинающих ИИ и машинного обучения на AWS».
    Универсальный ресурсный центр для изучения искусственного интеллекта и машинного обучения. НОЛЬ или ГЕРОЙ, начните свое путешествие здесь. Получите решения и пройдите обучение у экспертов AWS...

    5 простых концепций Python, ставших сложными
    #заранее извините 1) Переменные x = 4 y = 5 Переменная в Python — это символическое представление объекта. После присвоения некоторого объекта переменной Python мы приобретаем..

    «Освоение вероятности: изучение совместной, предельной, условной вероятности и теоремы Байеса —…
    Виды вероятности: Совместная вероятность Предельная вероятность Условная вероятность Диаграмма Венна в вероятностях: В “Set Theory” мы создаем диаграмму Венна...

    Основы Spring: Bean-компоненты, контейнер и внедрение зависимостей
    Как лего может помочь нашему пониманию Когда мы начинаем использовать Spring, нам бросают много терминов, и может быть трудно понять, что они все означают. Итак, мы разберем основы и будем..

    Отслеживание состояния с течением времени с дифференцированием снимков
    Время от времени что-то происходит и революционизирует часть моего рабочего процесса разработки. Что-то более забавное вместо типичного утомительного и утомительного процесса разработки. В..