__init__ как конструктор? - PullRequest
37 голосов
/ 05 июля 2011

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

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

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

Ответы [ 6 ]

35 голосов
/ 05 июля 2011

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

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

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

31 голосов
/ 05 июля 2011

Лично я нахожу, что "__init__ не конструктор" - это очень хорошая укладка волос.

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

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

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

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

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

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

5 голосов
/ 05 июля 2011

Конструктор возвращает экземпляр и может завершиться ошибкой.Но __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__, с другой стороны, возвращаетпример.

2 голосов
/ 21 июня 2016

С 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__() следует помнить несколько важных моментов:

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

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

0 голосов
/ 07 мая 2013

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

0 голосов
/ 05 июля 2011

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

...