You must have seen the implementation of the __init__
method in any Python class, and if you have worked with Python classes, you must have implemented the __init__
method many times. However, you are unlikely to have implemented or seen a __new__
method within any class.
In this article, we’ll see:
- Definition of the
__init__
and__new__
methods __init__
method and__new__
method implementation- When they should be used
- The distinction between the two methods
__init__ Vs __new__ Method
The __init__
method is an initializer method that is used to initialize the attributes of an object after it is created, whereas the __new__
method is used to create the object.
When we define both the __new__
and the __init__
methods inside a class, Python first calls the __new__
method to create the object and then calls the __init__
method to initialize the object’s attributes.
Most programming languages require only a constructor, a special method to create and initialize objects, but Python has both a constructor and an initializer.
Let’s talk about both these methods one by one and implement these methods inside a Python class.
__new__ Method
As stated already, the __new__
method is a constructor method used to create and return an object(instance of the class).
Syntax
object.__new__(cls, *args, **kwargs)
The __new__
method’s first parameter is cls
, which is a class of the object we want to create.
The *args
and **kwargs
parameters are not used by the __new__
method, but they must match the parameters of the class’s __init__
method.
Example
1 2 3 4 5 6 7 8 9 10 11 12 13 |
# Defined a base class class Name: # Created a __new__ method def __new__(cls): print(f'Called the __new__ method.') return super(Name, cls).__new__(cls) # Created an __init__ method def __init__(self): print(f"Called the __init__ method.") # Created an object Name() |
In the above code, we defined the __new__
and __init__
methods within the class Name
. The __new__
method accepts the cls
parameter, which is used to refer to the class Name
, and when called, it prints the message and returns the class instance using the super(Name, cls).__new__(cls)
.
One thing to note is that the Name
class is a base class, so we could have directly called the __new__
method on the object like this expression object.__new__(cls)
. However, the standard method is to use the super()
function.
The __init__
method is then called with the instance passed to the self
parameter.
Then we called the Name
class (Name()
), and when we run the code, we get the output shown below.
1 2 |
Called the __new__ method. Called the __init__ method. |
The output shows that the __new__
method is called first and then the __init__
method.
__init__ Method
As we saw in the above example, the __init__
method is called to initialize the attributes of the object as soon as the object is created.
Syntax
__init__(self, *args, **kwargs)
As a first parameter, the __init__
method accepts self
, which is used to refer to the class instance.
The parameters *args
and **kwargs
are used to initialize the instance variable with the values stored within them.
Example
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
# Defined a base class class Name: # Created a __new__ method def __new__(cls, name): print(f'Called the __new__ method.') return super(Name, cls).__new__(cls) # Created an __init__ method def __init__(self, name): print(f"Called the __init__ method.") self.name = name # Created an object name_obj = Name('Sachin') print(name_obj.name) |
In the __init__
method, we passed the name
parameter and did the same in the __new__
method to make the __new__
and __init__
method signature compatible with each other.
We called the class with the 'Sachin'
argument, which will automatically invoke the __init__
method and will initialize the instance variable self.name
with this value.
When we call the name
attribute(instance variable) on the object name_obj
, we’ll get the following output.
1 2 3 |
Called the __new__ method. Called the __init__ method. Sachin |
The name
attribute(instance variable) of the name_obj
is initialized to the value 'Sachin'
.
Implementation
Let’s define both __new__
and __init__
methods inside the class Language
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
class Language: def __new__(cls, *args): return super().__new__(cls) def __init__(self, lang, year): self.lang = lang self.year = year language = Language('Python', 1991) print(language.lang) print(language.year) ---------- Python 1991 |
We defined both __new__
and __init__
methods inside the class Language
and created the class object, when we run the code, Python will call the __new__
method which is responsible for creating and returning the object of the class, and then calls the __init__
method which is responsible for the initialization of the object’s attributes(instance variables).
Now we can access the attributes of the object lang
and year
using dot notation on the object language
as we did in the above code.
Every time we create a new object, the __init__
method is invoked, which means that if we don’t return super().__new__(cls)
, then the __init__
method will not execute and return None
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
class Language: def __new__(cls, *args): print("Creating") # Method not called def __init__(self, lang, year): print("Initializing") self.lang = lang self.year = year language = Language('Python', 1991) print(language) ---------- Creating None |
Let’s see what happens when we implement only the __init__
method inside a class.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
class Language: def __init__(self, lang, year): self.lang = lang self.year = year language = Language('Python', 1991) print(language.lang) print(language.year) ---------- Python 1991 |
The code works the same as the previous code which we saw at the beginning of this section.
When we instantiated the class using language = Language('Python', 1991)
, the expression is equivalent to the following:
1 2 |
language = object.__new__(Language) language.__init__('Python', 1991) |
If we try to print the language
object after calling the __new__
and the __init__
methods using the __dict__
, then we’ll get the following output:
1 2 3 4 5 6 7 8 |
language = object.__new__(Language) print(language.__dict__) language.__init__('Python', 1991) print(language.__dict__) ---------- {} {'lang': 'Python', 'year': 1991} |
We got an empty dictionary after calling the __new__
method because the object was created but not yet initialized, to initialize, we called the __init__
method explicitly and got the values.
When To Use
Use case of __new__
Consider the following example in which we are using the __new__
method to customize the object at the instantiation.
1 2 3 4 5 6 |
class Reverse(str): def __new__(cls, sequence): return super().__new__(cls, sequence[::-1]) seq = Reverse("GeekPython") print(seq) |
The above code defines the class Reverse
, which inherits from the str
built-in type, as well as the __new__
method that accepts a sequence
. We override the __new__
method to reverse the sequence
before creating the object.
1 |
nohtyPkeeG |
The argument "GeekPython"
passed to the Reverse
class got reversed due to sequence[::-1]
before the object is created.
This can’t be done using the __init__
method, if we try to do so, the result will be an error.
1 2 3 4 5 6 7 8 9 |
class Reverse(str): def __init__(self, sequence): super().__init__(sequence[::-1]) seq = Reverse("GeekPython") print(seq) ---------- TypeError: object.__init__() takes exactly one argument (the instance to initialize) |
Another use case of the __new__
method is creating a Singleton (design pattern that restricts the instantiation of a class to a single instance).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
class Singleton: # Created a private variable __ins = None # Defined the __new__ method def __new__(cls): if cls.__ins is None: print("Instance creating...") cls.__ins = super().__new__(cls) return cls.__ins # Creating object obj1 = Singleton() obj2 = Singleton() obj3 = Singleton() print(obj1) print(obj2) print(obj3) # Checking if they are all same print(obj1 is obj2 is obj3) |
In the above code, we defined the class Singleton
and created a private variable __obj
to store the class’s single instance, as well as a __new__
method that checks if the __ins
is None
, then creates a new instance and assigns it to the __ins
, and returns the existing instance if the __ins
is not None
.
Then we printed three instances of the Singleton
class named obj1
, obj2
, and obj3
and checked to see if they were all the same.
1 2 3 4 5 |
Instance creating... <__main__.Singleton object at 0x000001B3DFD5C130> <__main__.Singleton object at 0x000001B3DFD5C130> <__main__.Singleton object at 0x000001B3DFD5C130> True |
All three instances point to the same memory address, and we can see that we got True
, indicating that they are all the same.
Use case of __init__
The __init__
method is commonly used to initialize the object’s attributes with or without the default values.
1 2 3 4 5 6 7 8 9 10 |
class Language: def __init__(self, lang="Python", year=1991): self.lang = lang self.year = year def show(self): print(f'Language: {self.lang} | Founded: {self.year}.') language = Language() language.show() |
The above code defines a Language
class and the __init__
method, which accepts lang
and year
parameters with default values of "Python"
and 1991
, respectively.
When we call the Language
class without argument, the __init__
method will set the lang
and year
attributes to their default values.
1 |
Language: Python | Founded: 1991. |
Difference
Now that we’ve seen the definition, syntax, and implementation of both methods, we are now able to differentiate between them.
__new__ method | __init__ method |
The __new__ method is called first | The __init__ method is called after the __new__ method |
Used to create and return the object | Used to initialize the attributes of the object |
It is a constructor method | It is an initializer method |
Takes class as the first parameter | Takes the instance of the class as the first parameter |
Can be overridden to customize the object at the instantiation | Probably only be used to initialize the attributes of the object |
Conclusion
Python has a concept of a constructor and an initializer method. The __new__
method is a constructor method whereas the __init__
method is an initializer method. Python first calls the __new__
method which is responsible for the object creation and then calls the __init__
method which is responsible for the initialization of the object’s attributes.
🏆Other articles you might be interested in if you liked this one
✅Context managers and the with statement in Python.
✅What is abstract base class(ABC) in Python?
✅Public, Protected, and Private access modifiers in Python.
✅What are inheritance and different types of inheritance in Python?
✅What is enumerate() function in Python?
✅Execute dynamically generated code using the exec() in Python.
✅Async/Await – Asynchronous programming using asyncio in Python.
That’s all for now
Keep Coding✌✌