new in Python (original) (raw)
Python is an **object-oriented programming language, where everything is an object. Python provides several special methods, known as magic methods or dunder methods (dunder means double underscores), which enable powerful and flexible object-oriented capabilities. These methods start and end with double underscores (e.g., __init__, __add__, __len__, __repr__, etc.). One such powerful magic method is **__new__, which plays an important role in instance creation.
What is __new__ in Python?
Whenever a class is instantiated, two methods are called:
- **__new__ : Responsible for creating a new instance of the class.
- **__init__ : Initializes the instance.
Unlike **__init__, which is used for setting up an object after it has been created, **__new__ is responsible for creating and returning the new instance itself.
**Example:
Python `
class A: def new(cls): print("Creating instance") return super(A, cls).new(cls)
def __init__(self):
print("Initializing instance")A()
`
Output
Creating instance Initializing instance
**Explanation: __new__ method is called first to create an instance of class A and then returns the newly created instance. After that, the __init__ method initializes the instance.
**Syntax
class ClassName:
def __new__(cls, *args, **kwargs):
# Custom instance creation logic
instance = super(ClassName, cls).__new__(cls, *args, **kwargs)
return instance
**Parameters:
- **cls : The class itself.
- ***args : Positional arguments passed to __new__ .
- ****kwargs : Keyword arguments passed to **__new__ .
**Return Value:
- Must return an instance of the class (cls) or another class.
- If __new__ returns an object of another type, __init__ will not be called.
Alternative method
Instances can be created in __new__ using either:
instance = super(ClassName, cls).__new__(cls, *args, **kwargs)
or
instance = object.__new__(cls, *args, **kwargs)
If both **__new__ and **__init__ exist in a class, **__new__ executes first. It determines whether __init__ should be executed by either returning an instance of the class or bypassing __init__ by returning an instance of another class.
Examples of __new__ method
**Example 1: What happens if __new__ does not return an instance?
Python `
class A: def new(cls): print("Creating instance")
def __init__(self):
print("Initializing instance")print(A())
`
Output
Creating instance None
**Explanation: __new__ method does not return an instance of the class. Since __new__ must return an instance, but it lacks a return statement, it implicitly returns None.
**Example 2: Returning a different type from __new__
Python `
class A: def new(cls): print("Creating instance") return "Hello, World!"
print(A())
`
Output
Creating instance Hello, World!
**Explanation : __new__ method should return a new object of **class A, but here it returns the string "Hello, World!". Because of this, Python does not create an instance of **A, so the __init__ method is never called. Instead, print(A()) simply prints "Hello, World!".
**Example 3: Returning an instances of another class
Python `
class GeeksforGeeks: def str(self): return "GeeksforGeeks Instance"
class Geek: def new(cls): return GeeksforGeeks()
def __init__(self):
print("Inside init")print(Geek())
`
Output
GeeksforGeeks Instance
**Explanation :__new__ method of Geek returns an instance of GeeksforGeeks instead of Geek, so the __init__ method is never called. When print(Geek()) is executed, it prints "GeeksforGeeks Instance" from the **__str__ method of GeeksforGeeks.
**Example 4: Returning values from **__new__ and __init__
Python `
class A(object): def new(cls): print("Creating instance") return "GeeksforGeeks"
class B(object): def init(self): print("Initializing instance") return "GeeksforGeeks"
print(A()) print(B())
`
**Output
Hangup (SIGHUP)
Traceback (most recent call last):
File "/home/guest/sandbox/Solution.py", line 12, in
print(B())
~^^
TypeError: init() should return None, not 'str'
**Explanation: In **class A, the **__new__ method prints "Creating instance" and returns the string "GeeksforGeeks", so the **__init__ method is never called. This results in "GeeksforGeeks" being printed. In class B, the __init__ method incorrectly tries to return a string, but since __init__ must return None, it raises a **TypeError.
When to use __new__
**__new__ is rarely overridden, but it is useful in specific scenarios, such as:
- **Implementing Singleton Pattern: Ensures only one instance of a class exists.
- **Returning Cached Objects: Helps in memory optimization by reusing existing objects instead of creating new ones.
- **Immutable Object Creation: Used in classes like str and tuple since they are immutable.
- **Subclassing Immutable Types: When extending built-in immutable types like int, float or str.