backend / python core / 06_init_vs_new.md

Difference Between __init__() and __new__() in Python

3 interview angles 2 min read source

Difference Between __init__() and __new__() in Python

In Python, both __init__() and __new__() are special methods related to object creation, but they serve different purposes in the object lifecycle.

__new__():

  • Purpose: The __new__() method is responsible for creating a new instance of a class. It is called before __init__() and is used to actually create the object in memory.
  • Usage: This method is primarily used in metaclasses or when you need to customize object creation. In most cases, you don’t need to override it unless you are dealing with special cases (e.g., singletons, immutable objects).
  • Return Value: __new__() must return the newly created object (an instance of the class).
  • When It’s Called: __new__() is called before __init__() and can be thought of as creating the object, while __init__() is used to initialize it.

__init__():

  • Purpose: The __init__() method is responsible for initializing the newly created object. It’s called immediately after __new__() and is used to set up the object’s initial state.
  • Usage: This method is typically overridden in most classes to initialize attributes.
  • Return Value: __init__() does not return a value; it should always return None.
  • When It’s Called: __init__() is called after __new__() has created the object and is used to initialize it.

Key Differences:

Aspect __new__() __init__()
Purpose Creates a new object Initializes the newly created object
Return Value Returns the new object (instance) Returns None
When Called Called before __init__() Called after __new__()
Use Cases Customizing object creation (e.g., singletons, immutable types) Initializing object attributes

Example:

class MyClass:
    def __new__(cls, *args, **kwargs):
        print("Creating a new instance")
        instance = super().__new__(cls)  # Create the instance
        return instance

    def __init__(self, name):
        print("Initializing the instance")
        self.name = name

# Create an instance
obj = MyClass("John")

Output:

Creating a new instance
Initializing the instance
  • __new__() is responsible for creating the instance, and __init__() initializes it.

When to Use Each:

  • Override __new__() when you need control over object creation, such as when implementing design patterns like the Singleton pattern.
  • Override __init__() when you need to initialize the attributes of an object after it has been created.

In most cases, __init__() is the method you’ll need to work with, and __new__() is used in more advanced or specialized use cases.


class MyClass:
    def __new__(cls, *args, **kwargs):
        print("Creating a new instance")
        instance = super().__new__(cls)  # Create the instance
        return instance

    def __init__(self, name):
        print("Initializing the instance")
        self.name = name

# Create an instance
obj = MyClass("John")

Interview angle

  • __new__ versus __init__?” - __new__ creates and returns the instance; __init__ initialises the one already created. __new__ is a static method receiving the class, __init__ receives the instance.
  • “When do you override __new__?” - subclassing immutable types like tuple or str, implementing a singleton or instance cache, or returning an object of a different class. Rare in application code.
  • “What’s the trap?” - if __new__ returns something that isn’t an instance of the class, __init__ is never called. That silent skip is the bug people hit.