Должен ли init () вызывать init () родительского класса?



я использовал это в 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__()?



Edit: есть очень похожий вопрос: наследование и переопределение __init__ в Python

423   6  

6 ответов:

в Python, вызывая супер-класс'__init__ не является обязательным. Если вы его вызываете, то также необязательно использовать super идентификатор, или явное имя суперкласса:

object.__init__(self)

в случае объекта, вызов супер метода не является строго необходимым, так как супер метод пуст. То же самое для __del__.

ОТО, для __new__, вы действительно должны вызвать метод super и использовать его возврат в качестве вновь созданного объекта-если вы явно хочу вернуть что-то другое.

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

>>> class C(object):
    def __init__(self):
        self.b = 1


>>> class D(C):
    def __init__(self):
        super().__init__() # in Python 2 use super(D, self).__init__()
        self.a = 1


>>> class E(C):
    def __init__(self):
        self.a = 1


>>> d = D()
>>> d.a
1
>>> d.b  # This works because of the call to super's init
1
>>> e = E()
>>> e.a
1
>>> e.b  # This is going to fail since nothing in E initializes b...
Traceback (most recent call last):
  File "<pyshell#70>", line 1, in <module>
    e.b  # This is going to fail since nothing in E initializes b...
AttributeError: 'E' object has no attribute 'b'

__del__ то же самое, (но будьте осторожны, полагаясь на __del__ для завершения-рассмотрите возможность сделать это через оператор with вместо этого).

Я редко использую __new__. Я делаю все инициализация в __init__.

в ответе Анона:
"Если вам нужно что-то из супер __init__ должно быть сделано в дополнение к тому, что делается в текущем классе __init__, вы должны назвать это сами, так как это не произойдет автоматически"

это невероятно:он формулирует ровно противоположное принципу наследования.


это не "что-то из супер __init__ (...) не будет автоматически", это то, что это произойдет автоматически, но это не происходит, потому что базовый класс' __init__ исключен по определению производной-клас __init__

тогда зачем определять derived_class'__init__, поскольку он переопределяет то, что нацелено на то, когда кто-то прибегает к наследованию ??

это потому, что нужно определить то, что не сделано в базовом классе __init__ , и единственная возможность получить это, чтобы положить его выполнение в производном классе' .
Другими словами,нужно что-то в базовый класс' к тому, что будет автоматически сделано в базе-classe'__init__ Если этот последний не был исключен.
А не наоборот.


тогда проблема в том, что нужные инструкции присутствуют в базовом классе' __init__ больше не активируются в момент создания экземпляра. Чтобы компенсировать это инактивация, требуется что-то особенное: явный вызов базового класса' __init__ , чтобы сохранить, не добавляя, инициализация выполняется базовым классом'__init__ . Это именно то, что сказано в официальном документе:

переопределяющий метод в производном классе может на самом деле хотеть продлить вместо того, чтобы просто заменить метод базового класса С тем же именем. Существует простой способ прямого вызова метода базового класса: просто вызовите BaseClassName.methodname(self, arguments).
http://docs.python.org/tutorial/classes.html#inheritance

вот и вся история:

  • когда цель состоит в том, чтобы сохранить инициализацию, выполняемую базовым классом, то есть чистое наследование, ничего особенного не требуется, нужно просто избегать определения __init__ функция в производном классе

  • когда цель состоит в том, чтобы заменить инициализация выполняется базовым классом,__init__ должен быть определен в производном классе

  • когда целью является добавление процессов к инициализации, выполняемой базовым классом, производный класс'__init__ должен быть определен, содержащий явный вызов базового класса __init__


что я чувствую удивительным в посте Анона, так это не только то, что он выражает противоположность теории наследования, но и то, что то, что было 5 парней, проходящих мимо этого, не поворачивая головы, и, кроме того, никто не реагировал за 2 года в теме, интересную тему которой нужно читать относительно часто.

Edit: (после смены кода)
Мы не можем сказать вам, нужно ли вам звонить вашим родителям __init__ (или любая другая функция). Наследование, очевидно, будет работать без такого вызова. Все зависит от логики вашего кода: например, если все ваши __init__ делается в родительском классе, вы можете просто пропустить дочерний класс __init__ в целом.

рассмотрим следующий пример:

>>> class A:
    def __init__(self, val):
        self.a = val


>>> class B(A):
    pass

>>> class C(A):
    def __init__(self, val):
        A.__init__(self, val)
        self.a += val


>>> A(4).a
4
>>> B(5).a
5
>>> C(6).a
12

там нет жесткого и быстрого правила. Документация для класса должна указывать, должны ли подклассы вызывать метод суперкласса. Иногда вы хотите полностью заменить поведение суперкласса, а в другое время увеличить его - т. е. вызвать свой собственный код до и/или после вызова суперкласса.

обновление: та же основная логика применяется к любому вызову метода. Конструкторы иногда нуждаются в особом рассмотрении (поскольку они часто устанавливают состояние, которое определяет поведение) и деструкторы, потому что они параллельные конструкторы (например, при распределении ресурсов, например, соединения с базой данных). Но то же самое может относиться, скажем, к render() метод виджета.

уточнения: что такое OPP? Вы имеете в виду ООП? Нет - подкласс часто должен знать что-то о дизайне суперкласса. Не внутренние детали реализации-но основной контракт, который суперкласс имеет со своими клиентами (используя классы). Это не нарушает принципы ООП в любом случае. Вот почему protected является допустимым понятием в ООП в целом (хотя, конечно, в Python).

ИМО, вы должны назвать его. Если ваш суперкласс object, вы не должны, но в других случаях я думаю, что это исключительное не называть его. Как уже ответили другие, это очень удобно, если ваш класс даже не придется переопределить __init__ себя, например, когда у него нет (дополнительного) внутреннего состояния для инициализации.

Comments

    Ничего не найдено.