Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What can `__init__` do that `__new__` cannot?

In Python, __new__ is used to initialize immutable types and __init__ typically initializes mutable types. If __init__ were removed from the language, what could no longer be done (easily)?

For example,

class A:      def __init__(self, *, x, **kwargs):         super().__init__(**kwargs)         self.x = x   class B(A):      def __init__(self, y=2, **kwargs):         super().__init__(**kwargs)         self.y = y 

Could be rewritten using __new__ like this:

class A_N:      def __new__(cls, *, x, **kwargs):         obj = super().__new__(cls, **kwargs)         obj.x = x         return obj   class B_N(A_N):      def __new__(cls, y=2, **kwargs):         obj = super().__new__(cls, **kwargs)         obj.y = y         return obj 

Clarification for scope of question: This is not a question about how __init__ and __new__ are used or what is the difference between them. This is a question about what would happen if __init__ were removed from the language. Would anything break? Would anything become a lot harder or impossible to do?

like image 290
Neil G Avatar asked Feb 17 '16 09:02

Neil G


People also ask

Is def init necessary?

No, it is not necessary but it helps in so many ways. people from Java or OOPS background understand better. For every class instance, there is an object chaining that needs to complete when we instantiate any class by creating an object. If we don't put it compiler/interpreter puts it.

What is __ init __ constructor?

The __init__ method is the Python equivalent of the C++ constructor in an object-oriented approach. The __init__ function is called every time an object is created from a class. The __init__ method lets the class initialize the object's attributes and serves no other purpose. It is only used within classes.

Is constructor same as init?

But there's really two things going on when you call a constructor; a new object is created and then the constructor is called to initialise it. In C++/Java the "create a new object" part of that is invisible, whereas that can be exposed/customised in Python (via the __new__ method).

Is the __ init __ method technically a constructor in Python true or false and why or why not?

"__init__" is a reseved method in python classes. It is known as a constructor in object oriented concepts. This method called when an object is created from the class and it allow the class to initialize the attributes of a class.


2 Answers

Note about difference between __new__ and __init__

Before explaining missing functionality let's get back to definition of __new__ and __init__:

__new__ is the first step of instance creation. It's called first, and is responsible for returning a new instance of your class.

However, __init__ doesn't return anything; it's only responsible for initializing the instance after it's been created.

Consequences of replacing __init__ with __new__

Mainly you would lose out on flexibility. You would get a lot of semantics headaches and loose separation of initializatin and construction (by joining __new__ andinit we are to joining construction and initialization into one step...). Let's take a look on snippet below:

class A(object):     some_property = 'some_value'      def __new__(cls, *args, **kwargs):         obj = object.__new__(cls, *args, **kwargs)         obj.some_property = cls.some_property         return obj   class B(A):     some_property = 2      def __new__(cls, *args, **kwargs):         obj = super(B, cls).__new__(cls)         return obj 

Consequences of moving __init__ actions into __new__:

  1. Initialize B before A: When you are using __new__ method instead of __init__ your first step of creating new instance of B is calling A.__new__ as side effect you cannot initialize B before A is initialized ( access and assign some properties to new B instance). Using of __init__ gives you such flexability.

  2. Loose control on initializing order: let's imagine that you have B_N inherited from two classes (A_N1, A_N2), now you would miss controlling of order of initializing new instance of B_N(what is the order you are going to initialize instances ? it could be matter... what is weird.)

  3. Properties and methods mess: you would miss access to A.some_property (cls would be equal to B while instantiating new instance of B. However directly accessing of A.some_property is possible, but my guess it's at least weird to access properties within class throught class name and not by using classmethods).

  4. You cannot re-initialize an existed instance without creating new one or implementation special logic for this ( thanks to @platinhom for idea )

What can __init__ do that __new__ cannot?

There are no actions that cannot be done in __new__ and can in __init__, because actions that __init__ performs is a subset of the actions that can be performed by __new__.

An interesting moment from Python Docs, Pickling and unpickling normal class instances#object.getinitargs regarding when __init__ could be usefull:

When a pickled class instance is unpickled, its init() method is normally not invoked.

like image 112
Andriy Ivaneyko Avatar answered Sep 21 '22 05:09

Andriy Ivaneyko


Everything you can do in __init__ can also be done in __new__.

Then, why use __init__?
Because you don't have to store instance in variable (obj in your example code), and later bother returning it. You can focus on what you realy want to do – initializing mutable object.

like image 42
GingerPlusPlus Avatar answered Sep 24 '22 05:09

GingerPlusPlus