Вы можете определить один или оба из __new__
и __init__
.
__new__
должен возвращать объект - который может быть новым (как правило, эта задача делегируется type.__new__
), существующим (для реализации одиночных операций, «перезаписи» экземпляров из пула и т. Д.) или даже тот, который не экземпляр класса. Если __new__
возвращает экземпляр класса (новый или существующий), __init__
затем вызывается для него; если __new__
возвращает объект, который не является экземпляром класса, то __init__
является , а не вызванным.
__init__
передается экземпляру класса в качестве первого элемента (в том же состоянии __new__
возвращает его, т. Е. Обычно "пусто") и должен изменить его по мере необходимости, чтобы подготовить его к использованию (чаще всего путем добавления атрибуты).
В общем, лучше всего использовать __init__
для всего, что он может сделать - и __new__
, если что-то осталось, чего не может сделать __init__
, для этого "дополнительного чего-то".
Таким образом, вы обычно определяете и то, и другое, если есть что-то полезное, что вы можете сделать в __init__
, но не все, что вы хотите, чтобы произошло, когда создается экземпляр класса.
Например, рассмотрим класс, который подклассов int
, но также имеет слот foo
- и вы хотите, чтобы он был создан с помощью инициализатора для int
и одного для .foo
. Поскольку int
является неизменным, эта часть должна происходить в __new__
, так что педантично можно кодировать:
>>> class x(int):
... def __new__(cls, i, foo):
... self = int.__new__(cls, i)
... return self
... def __init__(self, i, foo):
... self.foo = foo
... __slots__ = 'foo',
...
>>> a = x(23, 'bah')
>>> print a
23
>>> print a.foo
bah
>>>
На практике для такого простого случая никто бы не возражал, если бы вы потеряли __init__
и просто переместили self.foo = foo
в __new__
. Но если инициализация богата и достаточно сложна, чтобы ее можно было лучше поместить в __init__
, то об этой идее стоит помнить.