Python new and init

__new__ and __init__ in Python

Differences between __new__() and __init__() methods in Python.

1 new()

__new__() method in Python class is responsible for creating a new instance object of the class. __new__() is similar to the constructor method in other OOP (Object Oriented Programming) languages such as C++ , Java and so on.

class Animal(object): def __new__(cls, *args, **kw): return super().__new__(cls) def eat(self): print('eat something!')

1.1 cls parameter

The first parameter cls represents the class being created.

Why the first parameter of __new__() method is the cls rather than the self ? Because the instance object has not been created yet and actually does not exist while the __new__() is calling, using self inside __new__() makes no sense.

1.2 Typical implementation

In most cases, you needn’t to implement __new__() yourself. Python implicitly provides a default and typical implementation of __new__() which will invoke the superclass’s __new__() method to create a new instance object and then return it. So following two definitions of the Animal class are equivalent indeed.

class Animal(object): def __new__(cls, *args, **kw): return super().__new__(cls) def eat(self): print('eat something!') class Animal(object): def eat(self): print('eat something!')

1.3 Return value

You don’t have to return a value in __new__() method.

If the __new__() method of your class returns an instance of cls , then the new instance’s __init__() method will be invoked automatically and the same arguments *args and **kw will be passed to the __init__() method as well.

Читайте также:  Javascript this style font size

If the __new__() method of your class doesn’t return an instance of cls , the __init__() method will not be called. So it allows you to take more control over how new instance objects are created and to return an instance object of an entirely different class if you like.

2 init()

The instance method __init__() is the initializer of a class. It is best to set initial values to attributes of an instance object in the __init__() method.

class Animal(object): def __init__(self, name): self.name = name

The __init__() method doesn’t have to return a value. Of course it can if you like, but Python will just ignore the returned value.

Although you can also set initial values in the __new__() method, it’s better to do initialization inside the __init__() .

NOT recommended:

class Animal(object): def __new__(cls, name): print('__new__() called.') obj = super().__new__(cls) obj.name = name return obj a = Animal('Bob') print(a.name)
class Animal(object): # Can be omitted, Python will give a default implementation def __new__(cls, *args, **kw): print('__new__() called.') print('args: ', args, ', kw: ', kw) return super().__new__(cls) def __init__(self, name): print('__init__() called.') self.name = name a = Animal('Bob') print(a.name)

As mentioned above, the __init__() and the __new__() will receive the same arguments except the first argument ( cls or self ). For example, the expression Animal(‘Bob’) will invoke __new__() with argument ‘Bob’ . After the __new__() returning the created Animal object, Python will call __init__() automatically and pass the argument Bob to it.

Источник

Constructors in Python (__init vs __new__)

Most object-oriented programming languages such as Java, C++, C#..etc have the concept of a constructor, a special method that creates and initializes the object when it is created. Python is a little different; it has a constructor and an initializer. The constructor function is rarely used unless you’re doing something exotic. So, we’ll start our discussion with the initialization method. The assumption in this article is that you already know the basics of classes and objects in python. The constructor function in python is called __new__ and __init__ is the initializer function. Quoting the python documentation, __new__ is used when you need to control the creation of a new instance while __init__ is used when you need to control the initialization of a new instance. __new__ is the first step of instance creation. It’s called first and is responsible for returning a new instance of your class. In contrast, __init__ doesn’t return anything; it’s only responsible for initializing the instance after it’s been created. In general, you shouldn’t need to override __new__ unless you’re subclassing an immutable type like str, int, Unicode, or tuple. NOTE:
Never name a function of your own with leading and trailing double underscores. It may mean nothing to Python, but there’s always the possibility that the designers of Python will add a function that has a special purpose with that name in the future, and when they do, your code will break.

Example 1: Using __init__

class Point: def __init__(self, data): self.num = data def print_num(self): print(self.num) obj = Point(100) obj.print_num() 

Output: 100 Note: The self parameter is a reference to the current instance of the class and is used to access variables that belong to the class.

Example 2:

class Person: def __new__(cls): return object.__new__(cls) def __init__(self): self.instance_method() def instance_method(self): print('success!') personObj = Person() 

Notice that __init__ receives the argument self, while __new__ receives the class (cls ). Since self is a reference to the instance, this should tell you quite evidently that the instance is already created by the time __init__ gets called, since it gets passed the instance. It’s also possible to call instance methods precisely because the instance has already been created. Thank you for reading. 😄
END.

Источник

Инстанцирование в Python

Какой метод вызывается первым при этом вызове Foo? Большинство новичков, да и, возможно, немало опытных питонистов тут же ответят: «метод __init__». Но если внимательно приглядеться к сниппетам выше, вскоре станет понятно, что такой ответ неверен.

__init__ не возвращает никакого результата, а Foo(1, y=2), напротив, возвращает экземпляр класса. К тому же __init__ принимает self в качестве первого параметра, чего не происходит при вызове Foo(1, y=2). Создание экземпляра происходит немного сложнее, о чём мы и поговорим в этой статье.

Порядок создания объекта

Инстанцирование в Python состоит из нескольких стадий. Понимание каждого шага делает нас чуть ближе к пониманию языка в целом. Foo — это класс, но в Питоне классы это тоже объекты! Классы, функции, методы и экземпляры — всё это объекты, и всякий раз, когда вы ставите скобки после их имени, вы вызываете их метод __call__. Так что Foo(1, y=2) — это эквивалент Foo.__call__(1, y=2). Причём метод __call__ объявлен в классе объекта Foo. Какой же класс у объекта Foo?

Так что класс Foo — это экземпляр класса type и вызов метода __call__ последнего возвращает класс Foo. Теперь давайте разберём, что из себя представляет метод __call__ класса type. Ниже находятся его реализации на C в CPython и в PyPy. Если надоест их смотреть, прокручивайте чуть дальше, чтобы найти упрощённую версию:

CPython

static PyObject * type_call(PyTypeObject *type, PyObject *args, PyObject *kwds) < PyObject *obj; if (type->tp_new == NULL) < PyErr_Format(PyExc_TypeError, "cannot create '%.100s' instances", type->tp_name); return NULL; > obj = type->tp_new(type, args, kwds); obj = _Py_CheckFunctionResult((PyObject*)type, obj, NULL); if (obj == NULL) return NULL; /* Ugly exception: when the call was type(something), don't call tp_init on the result. */ if (type == &PyType_Type && PyTuple_Check(args) && PyTuple_GET_SIZE(args) == 1 && (kwds == NULL || (PyDict_Check(kwds) && PyDict_Size(kwds) == 0))) return obj; /* If the returned object is not an instance of type, it won't be initialized. */ if (!PyType_IsSubtype(Py_TYPE(obj), type)) return obj; type = Py_TYPE(obj); if (type->tp_init != NULL) < int res = type->tp_init(obj, args, kwds); if (res < 0) < assert(PyErr_Occurred()); Py_DECREF(obj); obj = NULL; >else < assert(!PyErr_Occurred()); >> return obj; >

PyPy

def descr_call(self, space, __args__): promote(self) # invoke the __new__ of the type if not we_are_jitted(): # note that the annotator will figure out that self.w_new_function # can only be None if the newshortcut config option is not set w_newfunc = self.w_new_function else: # for the JIT it is better to take the slow path because normal lookup # is nicely optimized, but the self.w_new_function attribute is not # known to the JIT w_newfunc = None if w_newfunc is None: w_newtype, w_newdescr = self.lookup_where('__new__') if w_newdescr is None: # see test_crash_mro_without_object_1 raise oefmt(space.w_TypeError, "cannot create '%N' instances", self) w_newfunc = space.get(w_newdescr, self) if (space.config.objspace.std.newshortcut and not we_are_jitted() and isinstance(w_newtype, W_TypeObject)): self.w_new_function = w_newfunc w_newobject = space.call_obj_args(w_newfunc, self, __args__) call_init = space.isinstance_w(w_newobject, self) # maybe invoke the __init__ of the type if (call_init and not (space.is_w(self, space.w_type) and not __args__.keywords and len(__args__.arguments_w) == 1)): w_descr = space.lookup(w_newobject, '__init__') if w_descr is not None: # see test_crash_mro_without_object_2 w_result = space.get_and_call_args(w_descr, w_newobject, __args__) if not space.is_w(w_result, space.w_None): raise oefmt(space.w_TypeError, "__init__() should return None") return w_newobject

Если забыть про всевозможные проверки на ошибки, то коды выше примерно эквивалентны такому:

def __call__(obj_type, *args, **kwargs): obj = obj_type.__new__(*args, **kwargs) if obj is not None and issubclass(obj, obj_type): obj.__init__(*args, **kwargs) return obj

__new__ выделяет память под «пустой» объект и вызывает __init__, чтобы его инициализировать.

  1. Foo(*args, **kwargs) эквивалентно Foo.__call__(*args, **kwargs).
  2. Так как объект Foo — это экземпляр класса type, то вызов Foo.__call__(*args, **kwargs) эквивалентен type.__call__(Foo, *args, **kwargs).
  3. type.__call__(Foo, *args, **kwargs) вызывает метод type.__new__(Foo, *args, **kwargs), возвращающий obj.
  4. obj инициализируется при вызове obj.__init__(*args, **kwargs).
  5. Результат всего процесса — инициализированный obj.

Кастомизация

Теперь давайте переключим наше внимание на __new__. Этот метод выделяет память под объект и возвращает его. Вы вольны кастомизировать этот процесс множеством разных способов. Следует отметить, что, хотя __new__ и является статическим методом, вам не нужно объявлять его используя @staticmethod: интерпретатор обрабатывает __new__ как специальный случай.

Распространённый пример переопределения __new__ — создание Синглтона:

class Singleton(object): _instance = None def __new__(cls, *args, **kwargs): if cls._instance is None: cls._instance = super().__new__(cls, *args, **kwargs) return cls._instance
>>> s1 = Singleton() . s2 = Singleton() . s1 is s2 True

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

Другой пример переопределения __new__ — реализация паттерна Борг («Borg»):

class Borg(object): _dict = None def __new__(cls, *args, **kwargs): obj = super().__new__(cls, *args, **kwargs) if cls._dict is None: cls._dict = obj.__dict__ else: obj.__dict__ = cls._dict return obj
>>> b1 = Borg() . b2 = Borg() . b1 is b2 False >>> b1.x = 8 . b2.x 8

Учтите, что хотя примеры выше и демонстрируют возможности переопределения __new__, это ещё не значит что его обязательно нужно использовать:

__new__ — одна из самых частых жертв злоупотреблений. То, что может быть сделано переопределением этого метода, чаще всего лучше достигается другими средствами. Тем не менее, когда это действительно необходимо, __new__ — крайне полезный и мощный инструмент.

— Арион Спрэг, Хорошо забытое старое в Python

Редко можно встретить проблему в Python, где лучшим решением было использование __new__. Но когда у вас есть молоток, каждая проблема начинает выглядеть как гвоздь, поэтому всегда предпочитайте использованию нового мощного инструмента использование наиболее подходящего.

Источник

Оцените статью