Подтвердить что ты не робот

__init__ как конструктор?

Погружение в Python -

Было бы заманчиво, но неправильно назовите это конструктором класс. Это заманчиво, потому что выглядит как конструктор (по соглашению, __init__ - первый метод, определенный для класса), действует как один (это первая часть кода, выполненная в вновь созданный экземпляр класса), и даже звучит как один ( "init" конечно, предлагает конструктор-иш природа). Неверно, потому что объект уже была построена время __init__ вызывается, и вы уже имеют действительную ссылку на новый экземпляр класса.

Цитата предполагает, что некорректно вызывать __init__ как конструктор, потому что объект уже сконструирован к моменту времени __init__. Но! У меня всегда создавалось впечатление, что конструктор вызывается только после того, как объект сконструирован, потому что он по существу используется для инициализации элементов данных экземпляра, которые не имели бы смысла, если бы объект не существовал конструктором времени? (исходя из фона С++/Java)

4b9b3361

Ответ 1

Если у вас есть класс Foo, то:

  • Foo() - конструктор
  • Foo.__init__() является инициализатором
  • Foo.__new__() является распределителем

Построение объекта Python - это просто распределение нового экземпляра, за которым следует инициализация указанного экземпляра.

Ответ 2

Лично я считаю, что "__init__ не является конструктором", чтобы быть довольно тонким раскалыванием волос.

__init__ вызывается при запросе нового объекта. Предполагается использовать его аргументы для назначения атрибутов новому объекту, чтобы были установлены требуемые инварианты для нормальной работы объекта. Объект уже является допустимым ранее существующим местом для хранения атрибутов к моменту запуска кода в __init__. Новый объект обычно не имеет атрибутов, определенных на нем, когда код в __init__ начинает работать (кроме тех, что есть у всех объектов).

Вызывается конструктор С++ при запросе нового объекта. Предполагается использовать его аргументы для назначения поля на новом объекте таким образом, чтобы были установлены требуемые инварианты для нормальной работы объекта. Объект уже является допустимым ранее существовавшим местом для хранения полей к моменту запуска кода в конструкторе. Новый объект имеет все свои объявленные поля уже, когда код в конструкторе начинает работать, но они содержат мусор.

Вызывается Java-конструктор при запросе нового объекта. Предполагается использовать его аргументы для назначения поля на новом объекте таким образом, чтобы были установлены требуемые инварианты для нормальной работы объекта. Объект уже является допустимым ранее существовавшим местом для хранения полей к моменту запуска кода в конструкторе. Новый объект имеет все свои объявленные поля уже, когда код в конструкторе начинает работать со значениями по умолчанию.

Основное отличие метода __init__ и конструктора С++/Java находится в этом последнем предложении, которое я выделил, и это просто разница между статическим характером Java/С++ и динамической природой Python. Я не думаю, что это требует называть их принципиально разных концепций, на которые нельзя ссылаться одним и тем же словом.

Я думаю, что основная причина, по которой Pythonistas не нравится ссылаться на __init__, поскольку конструктор состоит в том, что люди думают о конструкторах С++/Java как о "создании нового объекта", потому что то, что они делают, когда вы их называете, Но на самом деле происходит две вещи, когда вы вызываете конструктора; создается новый объект, а затем его инициализирует конструктор. В С++/Java часть "создать новый объект" является невидимой, в то время как ее можно открыть/настроить в Python (с помощью метода __new__).

Итак, хотя роль метода __init__ очень похожа на роль конструктора С++/Java, некоторые люди предпочитают подчеркивать тот факт, что это не весь процесс, говоря, что "__init__ не является конструктор".

Ответ 3

Конструктор возвращает экземпляр и может выйти из строя. Но __init__ не возвращает экземпляр. Даже при возникновении __init__ и исключении, __del__ вызывается для удаления экземпляра.

Это можно увидеть здесь:

class A(object):
    def __init__(self):
        raise ValueError

    def __del__(self):
        print "Called"

def main():
    try:
        a = A()
    except ValueError, e:
        print "ValueError"

if __name__ == '__main__':
    main()

__new__, с другой стороны, возвращает экземпляр.

Ответ 4

В "Программирование Python: введение в информатику" от Джона Целле говорит: " Специальный метод __init__ является конструктором объекта. Python вызывает этот метод для инициализации нового объекта. Роль __init__ заключается в предоставлении начальных значений для переменных экземпляра объекта."

Ответ 5

Из http://www.programiz.com/article/python-self-why

__init__() не является конструктором

[..] Один важный вывод [..] заключается в том, что __init__() не является конструктором. Многие наивные программисты на Python путаются с ним, так как __init__() вызывается при создании объекта. Более пристальное наблюдение покажет, что первым параметром в __init__() является сам объект (объект уже существует). Функция __init__() вызывается сразу после создания объекта и используется для ее инициализации.

Технически говоря, конструктор - это метод, который создает сам объект. В Python этот метод __new__(). Общей сигнатурой этого метода является

__new__(cls, *args, **kwargs)

Относительно ответа, данного Беном, я бы сказал здесь, что большинство языков не следуют этому определению (полностью).

Далее

Когда вызывается __new__(), сам класс автоматически передается в качестве первого аргумента. Это то, что означает cls в указанной сигнатуре. Опять же, как self, cls - это просто соглашение об именах. Кроме того, *args и **kwargs используются для принятия произвольного количества аргументов во время вызовов метода в Python.

Некоторые важные моменты, которые следует помнить при реализации __new__():

  • __new__() всегда вызывается перед __init__().
  • Первый аргумент - это сам класс, который передается неявно.
  • Всегда возвращайте действительный объект из __new__(). Не обязательно, но в этом весь смысл.

Bottomline (для меня): __new__() представляется конструктором, а не __init__(), хотя все практические средства __init__() делают часть того, что большинство людей думает, что конструктор будет делать.

Ответ 6

__init__ не является конструктором, но по причинам, которые не будут иметь для вас значения, поскольку вы изучаете Python. Он ведет себя так, как вы привыкли к конструкторам, которые ведут себя на С++ и Java.