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?
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.
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.
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).
"__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.
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.
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__ and
init 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__
:
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.
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.)
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
).
You cannot re-initialize an existed instance without creating new one or implementation special logic for this ( thanks to @platinhom for idea )
__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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With