Я использовал это в Objective-C, у меня есть эта конструкция:
- (void)init {
if (self = [super init]) {
// init class
}
return self;
}
Должен ли Python также вызывать реализацию родительского класса для __init__
?
class NewClass(SomeOtherClass):
def __init__(self):
SomeOtherClass.__init__(self)
# init class
Это также верно / неверно для __new__()
и __del__()
?
Изменить: есть очень похожий вопрос: наследование и переопределение __init__
в Python
python
oop
superclass
Георг Шолли
источник
источник
object
был опечаткой. Но теперь у вас даже нетsuper
названия, к которому относится ваш вопрос.Ответы:
В Python вызов суперкласса не
__init__
является обязательным. Если вы его вызываете, то также необязательно, использовать лиsuper
идентификатор или явно указать суперкласс:В случае объекта вызов супер-метода не является строго необходимым, поскольку супер-метод пуст. То же самое для
__del__
.С другой стороны, для
__new__
, вы действительно должны вызвать супер-метод и использовать его возврат в качестве вновь созданного объекта - если вы явно не хотите вернуть что-то другое.источник
[super init]
, он был бы более распространенным. Просто спекулятивная мысль; суперконструкция в Python 2.x мне немного неудобна.Если вам нужно сделать что-то из super
__init__
в дополнение к тому, что делается в текущем классе,__init__,
вы должны вызвать это самостоятельно, поскольку это не произойдет автоматически. Но если от super'а ничего__init__,
не надо называть , не надо. Пример:__del__
точно так же (но не стоит полагаться на__del__
финализацию - подумайте о том, чтобы сделать это с помощью оператора with).Я редко использую
__new__.
Я делаю всю инициализацию в__init__.
источник
super(D,self).__init__()
В ответе Анона:
«Если вам нужно сделать что-то из суперспособности
__init__
в дополнение к тому, что делается в текущем классе,__init__
, вы должны вызвать это самостоятельно, поскольку это не произойдет автоматически»Это невероятно: он формулирует прямо противоположную принципу наследования.
Дело не в том, что «что-то из super
__init__
(...) не произойдет автоматически» , а в том, что это БУДЕТ происходить автоматически, но этого не происходит, потому что базовый класс '__init__
отменяется определением производного класса.__init__
Итак, ПОЧЕМУ определение производного_класса?
__init__
, поскольку он перекрывает то, на что нацелено, когда кто-то прибегает к наследованию ??Это потому, что нужно определить что-то, что НЕ выполняется в базовом классе
__init__
, и единственная возможность получить это - поместить его выполнение в функцию производного класса__init__
.Другими словами, в базовом классе нужно что-то «
__init__
в дополнение к тому, что автоматически делалось бы в базовом классе »,__init__
если бы последний не был переопределен.НЕ наоборот.
Тогда проблема в том, что желаемые инструкции, присутствующие в базовом классе
__init__
, больше не активируются в момент создания экземпляра. Чтобы компенсировать эту инактивацию, требуется кое-что особенное: явный вызов базового класса__init__
, «чтобы СОХРАНИТЬ , НЕ ДОБАВИТЬ, инициализацию, выполняемую базовым классом»__init__
. Это именно то, что сказано в официальном документе:Вот и вся история:
когда цель состоит в том, чтобы СОХРАНИТЬ инициализацию, выполняемую базовым классом, то есть чистое наследование, ничего особенного не требуется, нужно просто избегать определения
__init__
функции в производном классекогда целью является ЗАМЕНИТЬ инициализацию, выполняемую базовым классом, она
__init__
должна быть определена в производном классекогда цель состоит в том, чтобы ДОБАВИТЬ процессы к инициализации, выполняемой базовым классом,
__init__
должен быть определен производный класс , содержащий явный вызов базового класса__init__
Что меня удивляет в посте Анона, так это не только то, что он выражает противоположное теории наследования, но и то, что 5 парней прошли мимо, за которые проголосовали, не поворачиваясь, и, более того, никто не отреагировал за 2 года в ветка, интересная тема которой должна читаться относительно часто.
источник
Изменить : (после изменения кода)
Мы не можем сказать вам, нужно ли вам вызывать родительскую
__init__
(или любую другую функцию). Очевидно, что наследование работало бы без такого вызова. Все зависит от логики вашего кода: например, если вы все__init__
делаете в родительском классе, вы можете просто__init__
вообще пропустить дочерний класс .рассмотрим следующий пример:
источник
Нет жесткого правила. Документация для класса должна указывать, должны ли подклассы вызывать метод суперкласса. Иногда вы хотите полностью заменить поведение суперкласса, а в других случаях усилить его - т.е. вызвать свой собственный код до и / или после вызова суперкласса.
Обновление: та же базовая логика применяется к любому вызову метода. Конструкторы иногда нуждаются в особом внимании (поскольку они часто устанавливают состояние, которое определяет поведение) и деструкторы, поскольку они параллельны конструкторам (например, при распределении ресурсов, например, при подключении к базе данных). Но то же самое может относиться, скажем, к
render()
методу виджета.Дальнейшее обновление: что такое OPP? Вы имеете в виду ООП? Нет - подклассу часто нужно что- то знать о структуре суперкласса. Не внутренние детали реализации, а базовый контракт суперкласса со своими клиентами (с использованием классов). Это никоим образом не нарушает принципы ООП. Вот почему
protected
это правильная концепция в ООП в целом (хотя, конечно, не в Python).источник
ИМО, вы должны это назвать. Если ваш суперкласс есть
object
, вам не следует этого делать, но в других случаях я считаю исключительным не называть его. Как уже ответили другие, очень удобно, если вашему классу даже не нужно переопределять__init__
себя, например, когда у него нет (дополнительного) внутреннего состояния для инициализации.источник
Да, вы всегда должны
__init__
явно вызывать базовый класс в качестве хорошей практики кодирования. Если вы забудете об этом, это может вызвать небольшие проблемы или ошибки во время выполнения. Это верно, даже если__init__
не принимает никаких параметров. Это не похоже на другие языки, где компилятор неявно вызывает за вас конструктор базового класса. Python этого не делает!Основная причина постоянного вызова базового класса
_init__
заключается в том, что базовый класс обычно может создавать переменные-члены и инициализировать их значениями по умолчанию. Поэтому, если вы не вызовете init базового класса, ни один из этих кодов не будет выполнен, и вы получите базовый класс, не имеющий переменных-членов.Пример :
Это печатает ..
Запустите этот код .
источник