Essential Special Methods for Object Creation

Essential Special Methods for Object Creation

Image by Alexandra_Koch from Pixabay

In Python, objects are considered as first class citizen. Virtually everything, like integers, strings, functions, classes, modules and even types themselves are considered as object. Which means they all inherit similar properties and behaviors of objects. They can have attributes and methods, they can be passed as function arguments and even they can be returned from fuction.

Python also facilitates us to create objects when we need them. Python provides class type where we can group the related data together and also define their functionality. We can instantiate objects from those classes and serve out purposes.

The internal mechanism for creating objects in Python is not that much complex. Python uses some dunder or special methods to create and instantiate the objects. In this article we will explore those special methods that take part in object creation in Python.

__new__ Method

The __new__ is a static method that is responsible of creating the actual objects. Its responsibility also includes allocating the memory of the object as well. This method is called on the class itself before the __init__ method. This method takes the class object as first arguments and then takes other arguments.

class MyClass:
    def __new__(cls, *args, **kwargs):
        print("Creating instance with __new__")
        instance = super().__new__(cls)
        return instance

obj = MyClass(42)
# Creating instance with __new__

In the example above the call super().__new__(cls) actually creates the instance and returns it.

Although you can override this method but you have to do that rarely. You can use it to ensure that the object is of certain type. You can also use to to prevent creating more that one object of the class to implement the singleton pattern.

__init__ Method

The __init__ method is the constructor method in Python. It is called automatically after the object is created. It’s an instance method that takes the object as first argument and after that the other objects. The main responsibility of this method is to initialize the object’s attribute. It doesn’t return anything but initialize the object.

When the parent class also has the __init__ method implemented, it will override the parent’s init method. If you want to execute the parent’s init method as well them you have to call that explicitly using super().__init__([args...]).

class MyClass:
    def __init__(self, value):
        print("Initializing instance with __init__")
        self.value = value

obj = MyClass(42)
# Initializing instance with __init__

In the example above the self argument is the object itselt and we are also pasing a value which is assigned to the value attribute of the object.

__call__ Metaclass Method

You create an instance by calling the class name. Internally it invokes the __call__ method of the metaclass which is type. This call method is responsible of creating the object by calling the __new__ method of the class and initiating the object by calling __init__ method of the class. And it finally returns the newly created object.

class CustomMeta(type):
    def __call__(cls, *args, **kwargs):
        print("entering Meta_1.__call__()")
        rv = super().__call__(*args, **kwargs)
        print("exiting Meta_1.__call__()")
        return rv

class MyClass(metaclass=CustomMeta):
    def __new__(cls, *args, **kwargs):
        print("Entering Class: Creating instance with __new__")
        instance = super().__new__(cls)
        print("Exiting Class: Creating instance with __new__")
        return instance

    def __init__(self, value):
        print("Init Class: Initializing instance with __init__")
        self.value = value

obj = MyClass(42)

# entering Meta_1.__call__()
# Entering Class: Creating instance with __new__
# Exiting Class: Creating instance with __new__
# Init Class: Initializing instance with __init__
# exiting Meta_1.__call__()

__del__ Method

The __del__ method is for deleting an object. It is also called a destructor. When the reference count on an object reaches to zero, this method gets called.

Although this method is not a part of object creation but it is important while deestroying an object. That’s why we have discussed this method here in this article.

If the base class also implemented the del method then it must be explicitly called from the child method to perform deletion part of the base class.

class MyClass:
    def __init__(self, value):
        print("Init Class: Initializing instance with __init__")
        self.value = value

    def __del__(self):
        print("Deleting instance with __del__")

obj = MyClass(42)
del obj
# Deleting instance with __del__

In the above script, the obj has one reference count. When the del statement is executed the reference count became zero which triggers the method using obj.__del__().

Conclusion

As objects are the first class citizen in Python, understanding how the objects are created is a valuable skill for any Python developer. Knowing this also helps write better Python code. After reading this article you should have the understanding about the internal mechanism of how Python objects are created.


References
  1. Python __init__ vs __new__
  2. __init__ vs. __new__ Methods in Python
  3. Data Model
  4. Using the __call__ method of a metaclass instead of __new__?

Recent posts

LinkedIn
Reddit
Telegram