🕷️ Crawler Inspector

URL Lookup

Direct Parameter Lookup

Raw Queries and Responses

1. Shard Calculation

Query:
Response:
Calculated Shard: 197 (from laksa048)

2. Crawled Status Check

Query:
Response:

3. Robots.txt Check

Query:
Response:

4. Spam/Ban Check

Query:
Response:

5. Seen Status Check

ℹ️ Skipped - page is already crawled

📄
INDEXABLE
CRAWLED
2 hours ago
🤖
ROBOTS ALLOWED

Page Info Filters

FilterStatusConditionDetails
HTTP statusPASSdownload_http_code = 200HTTP 200
Age cutoffPASSdownload_stamp > now() - 6 MONTH0 months ago
History dropPASSisNull(history_drop_reason)No drop reason
Spam/banPASSfh_dont_index != 1 AND ml_spam_score = 0ml_spam_score=0
CanonicalPASSmeta_canonical IS NULL OR = '' OR = src_unparsedNot set

Page Details

PropertyValue
URLhttps://www.honeybadger.io/blog/python-instantiation-metaclass/
Last Crawled2026-04-17 08:25:00 (2 hours ago)
First Indexed2020-11-25 23:52:16 (5 years ago)
HTTP Status Code200
Meta TitleUnderstanding Object Instantiation and Metaclasses in Python - Honeybadger Developer Blog
Meta DescriptionIf you're coming to Python from another language, it's normal to feel a little confused about object instantiation and inheritance - especially when people star...
Meta Canonicalnull
Boilerpipe Text
In this article, we will cover the object instantiation process followed by Python internally to create objects. I'll start with the fundamentals of object creation, and then we'll dive deep into understanding specific methods, such as __new__ , __init__ , and __call__ . We will also understand the Metaclass in Python, along with its role in the object creation process. Although these are advanced topics, the article explains each topic step-by-step and from scratch so that even beginners can understand it. Please note that this article is written with Python3 in mind. Table of Contents Internals of Object Instantiation and Metaclass in Python Table of Contents The object base class in Python3 Objects and types in Python Metaclass in Python The object instantiation process in Python The __new__ method Override the __new__ method The __init__ method The __call__ method callable() Conclusion References The object base class in Python3 In Python3, all classes implicitly inherit from the built-in object base class. The object class provides some common methods, such as __init__ , __str__ , and __new__ , that can be overridden by the child class. Consider the code below, for example: class Human : pass In the above code, the Human class does not define any attributes or methods. However, by default, the Human class inherits the object base class and as a result it has all the attributes and methods defined by the object base class. We can check all the attributes and the methods inherited or defined by the Human class using the dir function. The dir function returns a list of all the attributes and methods defined on any Python object. dir (Human) # Output: [ '__class__' , '__delattr__' , '__dict__' , '__dir__' , '__doc__' , '__eq__' , '__format__' , '__ge__' , '__getattribute__' , '__gt__' , '__hash__' , '__init__' , '__init_subclass__' , '__le__' , '__lt__' , '__module__' , '__ne__' , '__new__' , '__reduce__' , '__reduce_ex__' , '__repr__' , '__setattr__' , '__sizeof__' , '__str__' , '__subclasshook__' , '__weakref__' ] The dir function's output shows that the Human class has lots of methods and attributes, most of which are available to the Human class from the object base class. Python provides a __bases__ attribute on each class that can be used to obtain a list of classes the given class inherits. The __bases__ property of the class contains a list of all the base classes that the given class inherits. print (Human. __bases__ ) # Output: (<class 'object'>,) The above output shows that the Human class has object as a base class. We can also look at the attributes and methods defined by the object class using the dir function. dir ( object ) # Output: [ '__class__' , '__delattr__' , '__dir__' , '__doc__' , '__eq__' , '__format__' , '__ge__' , '__getattribute__' , '__gt__' , '__hash__' , '__init__' , '__init_subclass__' , '__le__' , '__lt__' , '__ne__' , '__new__' , '__reduce__' , '__reduce_ex__' , '__repr__' , '__setattr__' , '__sizeof__' , '__str__' , '__subclasshook__' ] The above definition of the Human class is equivalent to the following code; here, we are explicitly inheriting the object base class. Although you can explicitly inherit the object base class, it's not required! class Human ( object ): pass object base class provides __init__ and __new__ methods that are used for creating and initializing objects of a class. We will discuss __init__ and __new__ in detail in the latter part of the tutorial. Objects and types in Python Python is an object-oriented programming language. Everything in Python is an object or an instance. Classes, functions, and even simple data types, such as integer and float, are also objects of some class in Python. Each object has a class from which it is instantiated. To get the class or the type of object, Python provides us with the type function and __class__ property defined on the object itself. Let's understand the type function with the help of simple data types, such as int and float . # A simple integer data type a = 9 # The type of a is int (i.e., a is an object of class int) type (a) # Output: <class 'int'> # The type of b is float (i.e., b is an object of the class float) b = 9.0 type (b) # Output: <class 'float'> Unlike other languages, in Python, 9 is an object of class int , and it is referred by the variable a . Similarly, 9.0 is an object of class float and is referred by the variable b . type is used to find the type or class of an object. It accepts an object whose type we want to find out as the first argument and returns the type or class of that object. We can also use the __class__ property of the object to find the type or class of the object. __class__ is an attribute on the object that refers to the class from which the object was created. a . __class__ # Output: <class 'int'> b . __class__ # Output: <class 'float'> After simple data types, let's now understand the type function and __class__ attribute with the help of a user-defined class, Human . Consider the Human class defined below: # Human class definition class Human : pass # Creating a Human object human_obj = Human () The above code creates an instance human_obj of the Human class. We can find out the class (or type of human_obj ) from which human_obj was created using either the type function or the __class__ property of the human_obj object. # human_obj is of type Human type (human_obj) # Output: <class '__main__.Human'> human_obj . __class__ # Output: <class '__main__.Human'> The output of type(human_obj) and human_obj.__class__ shows that human_obj is of type Human (i.e., human_obj has been created from the Human class). As functions are also objects in Python, we can find their type or class using the type function or the __class__ attribute. # Check the type of the function def simple_function (): pass type (simple_function) # Output: <class 'function'> simple_function . __class__ # Output: <class 'function'> Thus, simple_function is an object of the class function . Classes from which objects are created are also objects in Python. For example, the Human class (from which human_obj was created) is an object in itself. Yes, you heard it right! Even classes have a class from which they are created or instantiated. Let's find out the type or class of the Human class. class Human : pass type (Human) # Output: <class 'type'> Human . __class__ # Output: <class 'type'> Thus, the above code shows that the Human class and every other class in Python are objects of the class type . This type is a class and is different from the type function that returns the type of object. The type class, from which all the classes are created, is called the Metaclass in Python. Let's learn more about metaclass. Metaclass in Python Metaclass is a class from which classes are instantiated or metaclass is a class of a class. Earlier in the article, we checked that variables a and b are objects of classes int and float , respectively. As int and float are classes, they should have a class or metaclass from which they are created. type ( int ) # Output: <class 'type'> type ( float ) # Output: <class 'type'> # Even type of object class is - type type ( object ) # Output: <class 'type'> Thus, the type class is the metaclass of int and float classes. The type class is even the metaclass for the built-in object class, which is the base class for all the classes in Python. As type itself is a class, what is the metaclass of the type class? The type class is a metaclass of itself! type ( type ) # Output: <class 'type'> Metaclass is the least talked about topic and is not normally used very much in daily programming. I delve into this topic because metaclass plays an essential role in the object creation process that we will cover later in the article. The two important concepts that we have covered so far are as follows: All classes in Python are objects of the type class, and this type class is called Metaclass . Each class in Python, by default, inherits from the object base class. The object instantiation process in Python With a basic understanding of the Metaclass and objects in Python, let's now understand the object creation and initialization process in Python. Consider the Human class, as defined below: class Human : def __init__ ( self , first_name , last_name ): self . first_name = first_name self . last_name = last_name human_obj = Human ( "Virat" , "Kohli" ) isinstance (human_obj, Human) # Output: True # As object is the base class for all the class hence # isinstance(human_obj, object) is True isinstance (human_obj, object ) # Output: True The output of the above code shows that human_obj is an instance of class Human with the first_name as Virat and the last_name as Kohli . If we look at the above code closely, it's natural to have some questions: Per the definition of the Human class, we don't return anything from the __init__ method; how does calling the Human class return the human_obj ? We know that the __init__ method is used for initializing the object, but how does the __init__ method get self ? In this section, we will discuss each of these questions in detail and answer them. Object creation in Python is a two-step process. In the first step, Python creates the object, and in the second step, it initializes the object. Most of the time, we are only interested in the second step (i.e., the initialization step). Python uses the __new__ method in the first step (i.e., object creation) and uses the __init__ method in the second step (i.e., initialization). If the class does not define these methods, they are inherited from the object base class. As the Human class does not define the __new__ method, during the object instantiation process, the __new__ method of the object 's class is called, while for initialization, the __init__ method of the Human class is called. Next, we'll cover each of these methods in detail. The __new__ method The __new__ method is the first step in the object instantiation process. It is a static method on the object class and accepts cls or the class reference as the first parameter. The remaining arguments( Virat and Kohli ) are passed while calling the class - Human("Virat", "Kohli") . The __new__ method creates an instance of type cls (i.e., it allocates memory for the object by invoking the superclass' i.e. object class' __new__ method using super().__new__(cls) ). It then returns the instance of type cls . Usually, it does not do any initialization, as that is the job of the __init__ method. However, when you override the __new__ method, you can also use it to initialize the object or modify it as required before returning it. __new__ method signature # cls - is the mandatory argument. Object returned by the __new__ method is of type cls @ staticmethod def __new__ (cls[,...]): pass Override the __new__ method We can modify the object creation process by overriding the __new__ method of the object class. Consider the example below: class Human : def __new__ ( cls , first_name = None ): # cls = Human. cls is the class using which the object will be created. # Created object will be of type cls. # We must call the object class' __new__ to allocate memory obj = super (). __new__ (cls) # This is equivalent to object.__new__(cls) # Modify the object created if first_name : obj . name = first_name else : obj . name = "Virat" print ( type (obj)) # Prints: <__main__.Human object at 0x103665668> # return the object return obj # Create an object # __init__ method of `object` class will be called. virat = Human () print (virat.name) # Output: Virat sachin = Human ( "Sachin" ) print (sachin.name) # Output: Sachin In the above example, we have overridden the __new__ method of the object class. It accepts the first arguments as cls - a class reference to the Human class. The __new__ method is a special case in Python. Although it's a static method of the object class, on overriding it, we do not have to decorate it with the staticmethod decorator. Inside the __new__ method of the Human class, we are first calling the __new__ method of the object class using super().__new__(cls) . The object class' __new__ method creates and returns the instance of the class, which is passed as an argument to the __new__ method. Here, as we are passing cls (i.e., the Human class reference); the object 's __new__ method will return an instance of type Human . We must call the object class' __new__ method inside the overridden __new__ method to create the object and allocate memory to the object. The __new__ method of the Human class modifies the obj returned from the __new__ method of the object class and adds the name property to it. Thus, all objects created using the Human class will have a name property. Voila! We have modified the object instantiation process of the Human class. Let's consider another example. In this example, we are creating a new class called Animal and overriding the __new__ method. Here, when we are calling the __new__ method of the object class from the __new__ method of the Animal class, instead of passing the Animal class reference as an argument to the __new__ method of the object class, we are passing the Human class reference. Hence, the object returned from the __new__ method of the object class will be of type Human and not Animal . As a result, the object returned from calling the Animal class (i.e., Animal() ) will be of type Human . class Animal : def __new__ ( cls ): # Passing Human class reference instead of Animal class reference obj = super (). __new__ (Human) # This is equivalent to object.__new__(Human) print ( f "Type of obj: {type (obj) } " ) # Prints: Type of obj: <class '__main__.Human'> # return the object return obj # Create an object cat = Animal () # Output: # Type of obj: <class '__main__.Human'> type (cat) # Output: <class '__main__.Human'> The __init__ method The __init__ method is the second step of the object instantiation process in Python. It takes the first argument as an object or instance returned from the __new__ method. The remaining arguments are the arguments passed while calling the class (Human("Virat", "Kohli")) . These arguments are used for initializing the object. The __init__ method must not return anything. If you try to return anything using the __init__ method, it will raise an exception, as shown below: class Human : def __init__ ( self , first_name ): self . first_name = first_name return self human_obj = Human ( 'Virat' ) # Output: TypeError: __init__() should return None, not 'Human' Consider a simple example to understand both the __new__ and __init__ method. class Human : def __new__ ( cls , * args , ** kwargs ): # Here, the __new__ method of the object class must be called to create # and allocate the memory to the object print ( "Inside new method" ) print ( f "args arguments { args } " ) print ( f "kwargs arguments { kwargs } " ) # The code below calls the __new__ method of the object's class. # Object class' __new__ method allocates a memory # for the instance and returns that instance human_obj = super (Human, cls). __new__ (cls) print ( f "human_obj instance - { human_obj } " ) return human_obj # As we have overridden the __init__ method, the __init__ method of the object class will not be called def __init__ ( self , first_name , last_name ): print ( "Inside __init__ method" ) # self = human_obj returned from the __new__ method self . first_name = first_name self . last_name = last_name print ( f "human_obj instance inside __init__ { self } : { self.first_name } , { self.last_name } " ) human_obj = Human ( "Virat" , "Kohli" ) # Output # Inside new method # args arguments ('Virat', 'Kohli') # kwargs arguments {} # human_obj instance - <__main__.Human object at 0x103376630> # Inside __init__ method # human_obj instance inside __init__ <__main__.Human object at 0x103376630>: Virat, Kohli In the above code, we have overridden both the __new__ and __init__ method of the object 's class. __new__ creates the object ( human_obj ) of type Human class and returns it. Once the __new__ method is complete, Python calls the __init__ method with the human_obj object as the first argument. The __init__ method initializes the human_obj with first_name as Virat and last_name as Kohli . As object creation is the first step, and initialization is the second step, the __new__ method will always be called before the __init__ method Both __init__ and __new__ are called magic methods in Python. Magic methods have names that begin and end with __ (double underscores or "dunder"). Magic methods are called implicitly by the Python; you do not have to call them explicitly. For example, both the __new__ and __init__ method are called implicitly by Python. Let's cover one more magic method, __call__ . The __call__ method The __call__ method is a magic method in Python that is used to make the objects callable. Callable objects are objects that can be called. For example, functions are callable objects, as they can be called using the round parenthesis. Consider an example to better understand callable objects: def print_function (): print ( "I am a callable object" ) # print_function is callable as it can be called using round parentheses print_function () # Output # I am a callable object Let's try to call an integer object. As integer objects are not callable, calling them will raise an exception. a = 10 # As the integer object is not callable, calling `a` using round parentheses will raise an exception. a () # Output: TypeError: 'int' object is not callable callable() The callable function is used to determine whether an object is callable. The callable function takes the object reference as an argument and returns True if the object appears to be callable or False if the object is not callable. If the callable function returns True , the object might not be callable; however, if it returns False , then the object is certainly not callable. # Functions are callable callable (print_function) # Output: True # Interger object is not callable callable (a) # Output: False Let's determine whether the classes in Python are callable. Here, we will determine whether the Human class defined earlier is callable. callable (Human) # Output: True Yes, classes in Python are callable, and they should be! Don't you think so? When we call the class, it returns the instance of that class. Let's find out whether the objects created from the class are callable. human_obj = Human ( "Virat" , "Kohli" ) callable (human_obj) # Output: False # Let's try calling the human_obj human_obj () # As human_obj is not callable it raises an exception # Output: TypeError: 'Human' object is not callable So, human_obj is not callable though the class of human_obj (i.e., the Human class is callable). To make any object in Python callable, Python provides the __call__ method that needs to be implemented by the object's class. For example, to make human_obj object callable, the Human class has to implement the __call__ method. Once the Human class implements the __call__ method, all the objects of the Human class can be invoked like functions (i.e., using round parentheses). class Human : def __init__ ( self , first_name , last_name ): print ( "I am inside __init__ method" ) self . first_name = first_name self . last_name = last_name def __call__ ( cls ): print ( "I am inside __call__ method" ) human_obj = Human ( "Virat" , "Kohli" ) # Output: I am inside __init__ method # Both human_obj() and human_obj.__call__() are equaivalent human_obj () # Output: I am inside __call__ method human_obj . __call__ () # Output: I am inside __call__ method callable (human_obj) # Output: True The above code output shows that after implementing the __call__ method on the Human class, human_obj becomes a callable object. We can call the human_obj using round parentheses (i.e., human_obj() ). When we use human_obj() , in the background, Python calls the __call__ method of the Human class. So, instead of calling human_obj as human_obj() , we can directly invoke the __call__ method on human_obj (i.e., human_obj.__call__() ). Both human_obj() and human_obj.__call__() are equivalent, and they are the same thing. For all objects that are callable, their classes must implement the __call__ method. We know that functions are a callable object, so its class (i.e., function ) must implement the __call__ method. Let's invoke the __call__ method on the print_function defined earlier. print_function . __call__ () # Output: I am a callable object In Python, class is also a callable object; therefore, it is a class 's class (metaclass) (i.e., the type class must have a call method defined on it). Hence, when we call Human() , in the background, Python calls the call method of the type class. Roughly, the __call__ method on the types class looks something like shown below. This is just for explanation purposes; we will cover the actual definition of the __call__ method later in the tutorial. class type : def __call__ (): # Called when class is called i.e. Human() print ( "type's call method" ) With an understanding of __call__ method and how calling the class calls the __call__ method of the type class, let's find out the answer to the following questions regarding the object initialization process: Who calls the __new__ and __init__ method? Who passes the self object to the __init__ method? As the __init__ method is called after the __new__ method, and the __init__ method does not return anything, how does calling the class return the object (i.e., how does calling the Human class return the human_obj object)? Consider an example of instantiating an object in Python. class Human : def __init__ ( self , first_name , last_name ): self . first_name = first_name self . last_name = last_name human_obj = Human ( "Virat" , "Kohli" ) We know that when we call the class (i.e., Human("Virat", "Kohli") ), the __call__ method of the type class is called. However, what is the definition of the types class' __call__ method? As we are talking about CPython, the type class' __call__ method definition is defined in C language. If we convert it into Python and simplify it, it will look somewhat like this: # type's __call__ method which gets called when Human class is called i.e. Human() def __call__ ( cls , * args , ** kwargs ): # cls = Human class # args = ["Virat", "Kohli"] # Calling __new__ method of the Human class, as __new__ method is not defined # on Human, __new__ method of the object class is called human_obj = cls . __new__ ( * args, ** kwargs) # After __new__ method returns the object, __init__ method will only be called if # 1. human_obj is not None # 2. human_obj is an instance of class Human # 3. __init__ method is defined on the Human class if human_obj is not None and isinstance (human_obj, cls) and hasattr (human_obj, '__init__' ): # As __init__ is called on human_obj, self will be equal to human_obj in __init__ method human_obj . init ( * args, ** kwargs) return human_obj Let's understand the above code; when we do Human("Virat", "Kohli") , in the background, Python will call the type class' __call__ method, which is defined like the above code snippet. As shown above, the type class' __call__ method accepts Human class as the first argument ( cls is Human class), and the remaining arguments are passed while calling the Human class. The type class' __call__ method will first call the __new__ method defined on the Human class, if any; otherwise, the __new__ method of the Human class' parent class (i.e. the object 's __new__ method) is called. The __new__ method will return the human_obj . Now, the __call__ method of the type class will call the __init__ method defined on the Human class with human_obj as the first argument. __init__ will initialize the human_obj with the passed arguments, and finally, the __call__ method will return the human_obj . So, following steps are followed while creating and initializing an object in Python: Call the Human class - Human() ; this internally calls the __call__ method of the type class (i.e., type.__call__(Human, "Virat", "Kohli") ). type.__call__ will first call the __new__ method defined on the Human class. If the __new__ method is not defined on the Human class, the __new__ method of the object class will be called. The __new__ method will the return the object of type Human i.e. human_obj Now, type.__call__ will call the __init__ method defined on the Human class with human_obj as the first argument. This human_obj will be self in the __init__ method. The __init__ method will initialize the human_obj with the first_name as Virat and the last_name as Kohli . The __init__ method will not return anything. In the end, type.__call__ will return the human_obj object. As per the type.__call__ definition, whenever we create a new object, the __new__ method will always be called, but calling the __init__ method depends on the output of the __new__ method. The __init__ method will be called only if the __new__ method returns an object of type Human class or a subclass of the Human class. Let's understand some of the cases. Case 1 : If the returned object from the __new__ method is of type Human (i.e., the class of the __init__ method), the __init__ method will be called. class Human : def __new__ ( cls , * args , ** kwargs ): print ( f "Creating the object with cls: { cls } and args: { args } " ) obj = super (). __new__ (cls) print ( f "Object created with obj: { obj } and type: {type (obj) } " ) return obj def __init__ ( self , first_name , last_name ): print ( f "Started: __init__ method of Human class with self: { self } " ) self . first_name = first_name self . last_name = last_name print ( f "Ended: __init__ method of Human class" ) human_obj = Human ( "Virat" , "Kohli" ) Output: # Creating the object with cls: <class '__main__.Human'> and args: ('Virat', 'Kohli') # Object created with obj: <__main__.Human object at 0x102f6a4e0> and type: <class '__main__.Human'> # Started: __init__ method of Human class with self: <__main__.Human object at 0x102f6a400> # Ended: __init__ method of Human class with self: <__main__.Human object at 0x102f6a400> Case 2 : If the __new__ method does not return anything, then __init__ will not be called. class Human : def __new__ ( cls , * args , ** kwargs ): print ( f "Creating the object with cls: { cls } and args: { args } " ) obj = super (). __new__ (cls) print ( f "Object created with obj: { obj } and type: {type (obj) } " ) print ( "Not returning object from __new__ method, hence __init__ method will not be called" ) def __init__ ( self , first_name , last_name ): print ( f "Started: __init__ method of Human class with self: { self } " ) self . first_name = first_name self . last_name = last_name print ( f "Ended: __init__ method of Human class" ) human_obj = Human ( "Virat" , "Kohli" ) Output: # Creating the object with cls: <class '__main__.Human'> and args: ('Virat', 'Kohli') # Object created with obj: <__main__.Human object at 0x102f6a5c0> and type: <class '__main__.Human'> # Not returning object from __new__ method, hence __init__ method will not be called In the above code, the __new__ method of the Human class is called; hence, obj of type Human is created (i.e., memory is assigned for obj ). However, as the __new__ method did not return human_obj , the __init__ method will not be called. Also, human_obj will not have the reference for the created object, as it was not returned from the __new__ method. print (human_obj). # Output: None Case 3 : The __new__ method returns an integer object. class Human : def __new__ ( cls , * args , ** kwargs ): print ( f "Creating the object with cls: { cls } and args: { args } " ) obj = super (). __new__ (cls) print ( f "Object created with obj: { obj } and type: {type (obj) } " ) print ( "Not returning object from __new__ method, hence __init__ method will not be called" ) return 10 def __init__ ( self , first_name , last_name ): print ( f "Started: __init__ method of Human class with self: { self } " ) self . first_name = first_name self . last_name = last_name print ( f "Ended: __init__ method of Human class" ) human_obj = Human ( "Virat" , "Kohli" ) In the above code, the __new__ method of the Human class is called; hence, obj of type Human is created (i.e., memory is assigned for obj ). However, the __new__ method did not return human_obj but an integer with value 10 , which is not of the Human type; hence, the __init__ method will not be called. Also, human_obj will not have the reference for the created object, but it will refer to an integer value of 10 . print (human_obj) # Output: 10 In scenarios where the __new__ method does not return the instance of the class and we want to initialize the object, we have to call the __init__ method, explicity, inside the __new__ method, as shown below: class Human : def __new__ ( cls , * args , ** kwargs ): print ( f "Creating the object with cls: { cls } and args: { args } " ) obj = super (). __new__ (cls) print ( f "Object created with obj: { obj } and type: {type (obj) } " ) print ( "Not returning object from __new__ method, hence __init__ method will not be called" ) obj . __init__ ( * args, ** kwargs) return 10 def __init__ ( self , first_name , last_name ): print ( f "Started: __init__ method of Human class with self: { self } " ) self . first_name = first_name self . last_name = last_name print ( f "Ended: __init__ method of Human class" ) human_obj = Human ( "Virat" , "Kohli" ) Output: # Creating the object with cls: <class '__main__.Human'> and args: ('Virat', 'Kohli') # Object created with obj: <__main__.Human object at 0x102f6a860> and type: <class '__main__.Human'> # Not returning object from __new__ method, hence __init__ method will not be called # Started: __init__ method of Human class with self: <__main__.Human object at 0x102f6a860> # Ended: __init__ method of Human class In the above case, the __new__ method returned an integer object; hence the human_obj value will be 10. print (human_obj) # Output: 10 Conclusion In this article, we explored the __new__ , __init__ , and __call__ magic methods and discussed Metaclass in Python. In doing so, we have a better understanding of the object creation and initialization processes in Python. References https://eli.thegreenplace.net/2012/04/16/python-object-creation-sequence https://realpython.com/python-metaclasses/#old-style-vs-new-style-classes https://docs.python.org/3/reference/datamodel.html#special-method-names
Markdown
[Honeybadger ![Honeybadger homepage](https://www.honeybadger.io/_astro/logo.C8JJJNhL.svg) ![Honeybadger homepage](https://www.honeybadger.io/_astro/logo-dark.B42c-pvU.svg)](https://www.honeybadger.io/) Open main menu Product Features [Error Tracking](https://www.honeybadger.io/tour/error-tracking/) [Logging & Observability](https://www.honeybadger.io/tour/logging-observability/) [Dashboards & APM](https://www.honeybadger.io/tour/dashboards/) [Uptime Monitoring](https://www.honeybadger.io/tour/uptime-monitoring/) [Cron & Heartbeat Monitoring](https://www.honeybadger.io/tour/cron-job-heartbeat-monitoring/) [Status Pages](https://www.honeybadger.io/tour/status-pages/) Languages [Ruby](https://www.honeybadger.io/for/ruby/) [JavaScript](https://www.honeybadger.io/for/javascript/) [Python](https://www.honeybadger.io/for/python/) [Elixir](https://www.honeybadger.io/for/elixir/) [PHP](https://www.honeybadger.io/for/php/) [All languages](https://www.honeybadger.io/platforms/) Integrations [GitHub](https://www.honeybadger.io/integrations/github/) [Slack](https://www.honeybadger.io/integrations/slack/) [Datadog](https://www.honeybadger.io/vs/datadog/) [PagerDuty](https://www.honeybadger.io/integrations/pagerduty/) [All integrations](https://www.honeybadger.io/integrations/) [Pricing](https://www.honeybadger.io/plans/) [Changelog](https://www.honeybadger.io/changelog/) [Blog](https://www.honeybadger.io/blog/) [Log in](https://app.honeybadger.io/users/sign_in) [Start free trial](https://app.honeybadger.io/users/sign_up?plan=team) [Honeybadger ![](https://www.honeybadger.io/_astro/bolt.D0BsYe2K.svg) ![](https://www.honeybadger.io/_astro/bolt-dark.DI2bt8qx.svg)](https://www.honeybadger.io/) Close menu Product Features [Error Tracking](https://www.honeybadger.io/tour/error-tracking/) [Logging & Observability](https://www.honeybadger.io/tour/logging-observability/) [Dashboards & APM](https://www.honeybadger.io/tour/dashboards/) [Uptime Monitoring](https://www.honeybadger.io/tour/uptime-monitoring/) [Cron & Heartbeat Monitoring](https://www.honeybadger.io/tour/cron-job-heartbeat-monitoring/) [Status Pages](https://www.honeybadger.io/tour/status-pages/) Languages [Ruby](https://www.honeybadger.io/for/ruby/) [JavaScript](https://www.honeybadger.io/for/javascript/) [Python](https://www.honeybadger.io/for/python/) [Elixir](https://www.honeybadger.io/for/elixir/) [PHP](https://www.honeybadger.io/for/php/) [All languages](https://www.honeybadger.io/platforms/) Integrations [GitHub](https://www.honeybadger.io/integrations/github/) [Slack](https://www.honeybadger.io/integrations/slack/) [Datadog](https://www.honeybadger.io/vs/datadog/) [PagerDuty](https://www.honeybadger.io/integrations/pagerduty/) [All integrations](https://www.honeybadger.io/integrations/) [Pricing](https://www.honeybadger.io/plans/) [Changelog](https://www.honeybadger.io/changelog/) [Blog](https://www.honeybadger.io/blog/) [Log in](https://app.honeybadger.io/users/sign_in) [Start free trial](https://app.honeybadger.io/users/sign_up?plan=team) [Book a demo](https://www.honeybadger.io/demo/) [Honeybadger Developer Blog](https://www.honeybadger.io/blog/) [Company updates](https://www.honeybadger.io/blog/company/) [Ruby](https://www.honeybadger.io/blog/ruby/) [JavaScript](https://www.honeybadger.io/blog/javascript/) [Python](https://www.honeybadger.io/blog/python/) [DevOps](https://www.honeybadger.io/blog/devops/) [Go](https://www.honeybadger.io/blog/go/) [Elixir](https://www.honeybadger.io/blog/elixir/) [Write for us](https://www.honeybadger.io/blog/write-for-us/) On this page - [Overview](https://www.honeybadger.io/blog/python-instantiation-metaclass/) - [Table of Contents](https://www.honeybadger.io/blog/python-instantiation-metaclass/#table-of-contents) - [The object base class in Python3](https://www.honeybadger.io/blog/python-instantiation-metaclass/#the-object-base-class-in-python3) - [Objects and types in Python](https://www.honeybadger.io/blog/python-instantiation-metaclass/#objects-and-types-in-python) - [The object instantiation process in Python](https://www.honeybadger.io/blog/python-instantiation-metaclass/#the-object-instantiation-process-in-python) - [The \_\_new\_\_ method](https://www.honeybadger.io/blog/python-instantiation-metaclass/#the-__new__-method) - [The \_\_init\_\_ method](https://www.honeybadger.io/blog/python-instantiation-metaclass/#the-__init__-method) - [The \_\_call\_\_ method](https://www.honeybadger.io/blog/python-instantiation-metaclass/#the-__call__-method) - [Conclusion](https://www.honeybadger.io/blog/python-instantiation-metaclass/#conclusion) - [References](https://www.honeybadger.io/blog/python-instantiation-metaclass/#references) - [Honeybadger Developer Blog](https://www.honeybadger.io/blog/) - [Company updates](https://www.honeybadger.io/blog/company/) - [Ruby](https://www.honeybadger.io/blog/ruby/) - [JavaScript](https://www.honeybadger.io/blog/javascript/) - [Python](https://www.honeybadger.io/blog/python/) - [DevOps](https://www.honeybadger.io/blog/devops/) - [Go](https://www.honeybadger.io/blog/go/) - [Elixir](https://www.honeybadger.io/blog/elixir/) - [Write for us](https://www.honeybadger.io/blog/write-for-us/) - [RSS Feed](https://www.honeybadger.io/blog/feed.xml) Nov 25, 2020 · [Rupesh Mishra](https://www.honeybadger.io/blog/authors/rupeshmishra/) · [.md](https://www.honeybadger.io/blog/python-instantiation-metaclass.md "View as Markdown") # Understanding Object Instantiation and Metaclasses in Python In this article, we will cover the object instantiation process followed by Python internally to create objects. I'll start with the fundamentals of object creation, and then we'll dive deep into understanding specific methods, such as `__new__`, `__init__`, and `__call__`. We will also understand the `Metaclass` in Python, along with its role in the object creation process. Although these are advanced topics, the article explains each topic step-by-step and from scratch so that even beginners can understand it. Please note that this article is written with Python3 in mind. ## Table of Contents - [Internals of Object Instantiation and Metaclass in Python](https://www.honeybadger.io/blog/python-instantiation-metaclass/#internals-of-object-instantiation-and-metaclass-in-python) - [Table of Contents](https://www.honeybadger.io/blog/python-instantiation-metaclass/#table-of-contents) - [The `object` base class in Python3](https://www.honeybadger.io/blog/python-instantiation-metaclass/#the-object-base-class-in-python3) - [Objects and types in Python](https://www.honeybadger.io/blog/python-instantiation-metaclass/#objects-and-types-in-python) - [Metaclass in Python](https://www.honeybadger.io/blog/python-instantiation-metaclass/#metaclass-in-python) - [The object instantiation process in Python](https://www.honeybadger.io/blog/python-instantiation-metaclass/#the-object-instantiation-process-in-python) - [The `__new__` method](https://www.honeybadger.io/blog/python-instantiation-metaclass/#the-__new__-method) - [Override the `__new__` method](https://www.honeybadger.io/blog/python-instantiation-metaclass/#override-the-__new__-method) - [The `__init__` method](https://www.honeybadger.io/blog/python-instantiation-metaclass/#the-__init__-method) - [The `__call__` method](https://www.honeybadger.io/blog/python-instantiation-metaclass/#the-__call__-method) - [callable()](https://www.honeybadger.io/blog/python-instantiation-metaclass/#callable) - [Conclusion](https://www.honeybadger.io/blog/python-instantiation-metaclass/#conclusion) - [References](https://www.honeybadger.io/blog/python-instantiation-metaclass/#references) ## The `object` base class in Python3 In Python3, all classes implicitly inherit from the built-in `object` base class. The `object` class provides some common methods, such as `__init__`, `__str__`, and `__new__`, that can be overridden by the child class. Consider the code below, for example: ``` class Human: pass ``` In the above code, the `Human` class does not define any attributes or methods. However, by default, the `Human` class inherits the `object` base class and as a result it has all the attributes and methods defined by the `object` base class. We can check all the attributes and the methods inherited or defined by the `Human` class using the `dir` function. > The `dir` function returns a list of all the attributes and methods defined on any Python object. ``` dir(Human) # Output: ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__'] ``` The `dir` function's output shows that the `Human` class has lots of methods and attributes, most of which are available to the `Human` class from the `object` base class. Python provides a `__bases__` attribute on each class that can be used to obtain a list of classes the given class inherits. > The `__bases__` property of the class contains a list of all the base classes that the given class inherits. ``` print(Human.__bases__) # Output: (<class 'object'>,) ``` The above output shows that the `Human` class has `object` as a base class. We can also look at the attributes and methods defined by the `object` class using the `dir` function. ``` dir(object) # Output: ['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__'] ``` The above definition of the `Human` class is equivalent to the following code; here, we are explicitly inheriting the `object` base class. Although you can explicitly inherit the object base class, it's not required\! ``` class Human(object): pass ``` `object` base class provides `__init__` and `__new__` methods that are used for creating and initializing objects of a class. We will discuss `__init__` and `__new__` in detail in the latter part of the tutorial. ![Object class as the base class in Python](https://www.honeybadger.io/images/blog/posts/python-instantiation-metaclass/inheritance.jpg) *** ## Objects and types in Python Python is an object-oriented programming language. Everything in Python is an object or an instance. Classes, functions, and even simple data types, such as integer and float, are also objects of some class in Python. Each object has a class from which it is instantiated. To get the class or the type of object, Python provides us with the `type` function and `__class__` property defined on the object itself. Let's understand the `type` function with the help of simple data types, such as `int` and `float`. ``` # A simple integer data type a = 9 # The type of a is int (i.e., a is an object of class int) type(a) # Output: <class 'int'> # The type of b is float (i.e., b is an object of the class float) b = 9.0 type(b) # Output: <class 'float'> ``` Unlike other languages, in Python, `9` is an object of class `int`, and it is referred by the variable `a`. Similarly, `9.0` is an object of class `float` and is referred by the variable `b`. > `type` is used to find the type or class of an object. It accepts an object whose type we want to find out as the first argument and returns the type or class of that object. We can also use the `__class__` property of the object to find the type or class of the object. > `__class__` is an attribute on the object that refers to the class from which the object was created. ``` a.__class__ # Output: <class 'int'> b.__class__ # Output: <class 'float'> ``` After simple data types, let's now understand the `type` function and `__class__` attribute with the help of a user-defined class, `Human`. Consider the `Human` class defined below: ``` # Human class definition class Human: pass # Creating a Human object human_obj = Human() ``` The above code creates an instance `human_obj` of the `Human` class. We can find out the class (or type of `human_obj`) from which `human_obj` was created using either the `type` function or the `__class__` property of the `human_obj` object. ``` # human_obj is of type Human type(human_obj) # Output: <class '__main__.Human'> human_obj.__class__ # Output: <class '__main__.Human'> ``` The output of `type(human_obj)` and `human_obj.__class__` shows that `human_obj` is of type `Human` (i.e., `human_obj` has been created from the `Human` class). As functions are also objects in Python, we can find their type or class using the `type` function or the `__class__` attribute. ``` # Check the type of the function def simple_function(): pass type(simple_function) # Output: <class 'function'> simple_function.__class__ # Output: <class 'function'> ``` Thus, `simple_function` is an object of the class `function`. > Classes from which objects are created are also objects in Python. For example, the `Human` class (from which `human_obj` was created) is an object in itself. Yes, you heard it right! Even classes have a class from which they are created or instantiated. Let's find out the type or class of the `Human` class. ``` class Human: pass type(Human) # Output: <class 'type'> Human.__class__ # Output: <class 'type'> ``` Thus, the above code shows that the `Human` class and every other class in Python are objects of the class `type`. This `type` is a class and is different from the `type` function that returns the type of object. The `type` class, from which all the classes are created, is called the `Metaclass` in Python. Let's learn more about metaclass. ### Metaclass in Python > Metaclass is a class from which classes are instantiated or metaclass is a class of a class. Earlier in the article, we checked that variables `a` and `b` are objects of classes `int` and `float`, respectively. As `int` and `float` are classes, they should have a class or metaclass from which they are created. ``` type(int) # Output: <class 'type'> type(float) # Output: <class 'type'> # Even type of object class is - type type(object) # Output: <class 'type'> ``` Thus, the `type` class is the metaclass of `int` and `float` classes. The `type` class is even the metaclass for the built-in `object` class, which is the base class for all the classes in Python. As `type` itself is a class, what is the metaclass of the `type` class? The `type` class is a metaclass of itself\! ``` type(type) # Output: <class 'type'> ``` ![Metaclass in Python](https://www.honeybadger.io/images/blog/posts/python-instantiation-metaclass/metaclass.png) Metaclass is the least talked about topic and is not normally used very much in daily programming. I delve into this topic because metaclass plays an essential role in the object creation process that we will cover later in the article. The two important concepts that we have covered so far are as follows: 1. All classes in Python are objects of the `type` class, and this `type` class is called `Metaclass`. 2. Each class in Python, by default, inherits from the `object` base class. ![Inheritance and metaclass in Python](https://www.honeybadger.io/images/blog/posts/python-instantiation-metaclass/combined.png) *** ## The object instantiation process in Python With a basic understanding of the `Metaclass` and objects in Python, let's now understand the object creation and initialization process in Python. Consider the `Human` class, as defined below: ``` class Human: def __init__(self, first_name, last_name): self.first_name = first_name self.last_name = last_name human_obj = Human("Virat", "Kohli") isinstance(human_obj, Human) # Output: True # As object is the base class for all the class hence # isinstance(human_obj, object) is True isinstance(human_obj, object) # Output: True ``` The output of the above code shows that `human_obj` is an instance of class `Human` with the `first_name` as `Virat` and the `last_name` as `Kohli`. If we look at the above code closely, it's natural to have some questions: 1. Per the definition of the `Human` class, we don't return anything from the `__init__` method; how does calling the `Human` class return the `human_obj`? 2. We know that the `__init__` method is used for initializing the object, but how does the `__init__` method get `self`? In this section, we will discuss each of these questions in detail and answer them. Object creation in Python is a two-step process. In the first step, Python creates the object, and in the second step, it initializes the object. Most of the time, we are only interested in the second step (i.e., the initialization step). Python uses the `__new__` method in the first step (i.e., object creation) and uses the `__init__` method in the second step (i.e., initialization). If the class does not define these methods, they are inherited from the `object` base class. As the `Human` class does not define the `__new__` method, during the object instantiation process, the `__new__` method of the `object`'s class is called, while for initialization, the `__init__` method of the `Human` class is called. Next, we'll cover each of these methods in detail. ## The `__new__` method The `__new__` method is the first step in the object instantiation process. It is a static method on the `object` class and accepts `cls` or the class reference as the first parameter. The remaining arguments(`Virat` and `Kohli`) are passed while calling the class - `Human("Virat", "Kohli")`. The `__new__` method creates an instance of type `cls` (i.e., it allocates memory for the object by invoking the superclass' i.e. `object` class' `__new__` method using `super().__new__(cls)`). It then returns the instance of type `cls`. Usually, it does not do any initialization, as that is the job of the `__init__` method. However, when you override the `__new__` method, you can also use it to initialize the object or modify it as required before returning it. `__new__` method signature ``` # cls - is the mandatory argument. Object returned by the __new__ method is of type cls @staticmethod def __new__(cls[,...]): pass ``` #### Override the `__new__` method We can modify the object creation process by overriding the `__new__` method of the `object` class. Consider the example below: ``` class Human: def __new__(cls, first_name=None): # cls = Human. cls is the class using which the object will be created. # Created object will be of type cls. # We must call the object class' __new__ to allocate memory obj = super().__new__(cls) # This is equivalent to object.__new__(cls) # Modify the object created if first_name: obj.name = first_name else: obj.name = "Virat" print(type(obj)) # Prints: <__main__.Human object at 0x103665668> # return the object return obj # Create an object # __init__ method of `object` class will be called. virat = Human() print(virat.name) # Output: Virat sachin = Human("Sachin") print(sachin.name) # Output: Sachin ``` In the above example, we have overridden the `__new__` method of the `object` class. It accepts the first arguments as `cls` - a class reference to the `Human` class. > The `__new__` method is a special case in Python. Although it's a static method of the `object` class, on overriding it, we do not have to decorate it with the `staticmethod` decorator. Inside the `__new__` method of the `Human` class, we are first calling the `__new__` method of the `object` class using `super().__new__(cls)`. The `object` class' `__new__` method creates and returns the instance of the class, which is passed as an argument to the `__new__` method. Here, as we are passing `cls` (i.e., the `Human` class reference); the `object`'s `__new__` method will return an instance of type `Human`. > We must call the `object` class' `__new__` method inside the overridden `__new__` method to create the object and allocate memory to the object. > > The `__new__` method of the `Human` class modifies the `obj` returned from the `__new__` method of the `object` class and adds the `name` property to it. Thus, all objects created using the `Human` class will have a `name` property. Voila! We have modified the object instantiation process of the `Human` class. Let's consider another example. In this example, we are creating a new class called `Animal` and overriding the `__new__` method. Here, when we are calling the `__new__` method of the `object` class from the `__new__` method of the `Animal` class, instead of passing the `Animal` class reference as an argument to the `__new__` method of the `object` class, we are passing the `Human` class reference. Hence, the object returned from the `__new__` method of the `object` class will be of type `Human` and not `Animal`. As a result, the object returned from calling the `Animal` class (i.e., `Animal()`) will be of type `Human`. ``` class Animal: def __new__(cls): # Passing Human class reference instead of Animal class reference obj = super().__new__(Human) # This is equivalent to object.__new__(Human) print(f"Type of obj: {type(obj)}") # Prints: Type of obj: <class '__main__.Human'> # return the object return obj # Create an object cat = Animal() # Output: # Type of obj: <class '__main__.Human'> type(cat) # Output: <class '__main__.Human'> ``` ## The `__init__` method The `__init__` method is the second step of the object instantiation process in Python. It takes the first argument as an object or instance returned from the `__new__` method. The remaining arguments are the arguments passed while calling the class `(Human("Virat", "Kohli"))`. These arguments are used for initializing the object. The `__init__` method must not return anything. If you try to return anything using the `__init__` method, it will raise an exception, as shown below: ``` class Human: def __init__(self, first_name): self.first_name = first_name return self human_obj = Human('Virat') # Output: TypeError: __init__() should return None, not 'Human' ``` Consider a simple example to understand both the `__new__` and `__init__` method. ``` class Human: def __new__(cls, *args, **kwargs): # Here, the __new__ method of the object class must be called to create # and allocate the memory to the object print("Inside new method") print(f"args arguments {args}") print(f"kwargs arguments {kwargs}") # The code below calls the __new__ method of the object's class. # Object class' __new__ method allocates a memory # for the instance and returns that instance human_obj = super(Human, cls).__new__(cls) print(f"human_obj instance - {human_obj}") return human_obj # As we have overridden the __init__ method, the __init__ method of the object class will not be called def __init__(self, first_name, last_name): print("Inside __init__ method") # self = human_obj returned from the __new__ method self.first_name = first_name self.last_name = last_name print(f"human_obj instance inside __init__ {self}: {self.first_name}, {self.last_name}") human_obj = Human("Virat", "Kohli") # Output # Inside new method # args arguments ('Virat', 'Kohli') # kwargs arguments {} # human_obj instance - <__main__.Human object at 0x103376630> # Inside __init__ method # human_obj instance inside __init__ <__main__.Human object at 0x103376630>: Virat, Kohli ``` In the above code, we have overridden both the `__new__` and `__init__` method of the `object`'s class. `__new__` creates the object (`human_obj`) of type `Human` class and returns it. Once the `__new__` method is complete, Python calls the `__init__` method with the `human_obj` object as the first argument. The `__init__` method initializes the `human_obj` with `first_name` as `Virat` and `last_name` as `Kohli`. As object creation is the first step, and initialization is the second step, the `__new__` method will always be called before the `__init__` method Both `__init__` and `__new__` are called magic methods in Python. Magic methods have names that begin and end with `__` (double underscores or "dunder"). Magic methods are called implicitly by the Python; you do not have to call them explicitly. For example, both the `__new__` and `__init__` method are called implicitly by Python. Let's cover one more magic method, `__call__`. ## The `__call__` method The `__call__` method is a magic method in Python that is used to make the objects callable. Callable objects are objects that can be called. For example, `functions` are callable objects, as they can be called using the round parenthesis. Consider an example to better understand callable objects: ``` def print_function(): print("I am a callable object") # print_function is callable as it can be called using round parentheses print_function() # Output # I am a callable object ``` Let's try to call an `integer` object. As `integer` objects are not callable, calling them will raise an exception. ``` a = 10 # As the integer object is not callable, calling `a` using round parentheses will raise an exception. a() # Output: TypeError: 'int' object is not callable ``` ### callable() The `callable` function is used to determine whether an object is callable. The `callable` function takes the object reference as an argument and returns `True` if the object appears to be callable or `False` if the object is not callable. If the `callable` function returns `True`, the object might not be callable; however, if it returns `False`, then the object is certainly not callable. ``` # Functions are callable callable(print_function) # Output: True # Interger object is not callable callable(a) # Output: False ``` Let's determine whether the classes in Python are callable. Here, we will determine whether the `Human` class defined earlier is callable. ``` callable(Human) # Output: True ``` Yes, classes in Python are callable, and they should be! Don't you think so? When we call the class, it returns the instance of that class. Let's find out whether the objects created from the class are callable. ``` human_obj = Human("Virat", "Kohli") callable(human_obj) # Output: False # Let's try calling the human_obj human_obj() # As human_obj is not callable it raises an exception # Output: TypeError: 'Human' object is not callable ``` So, `human_obj` is not callable though the class of `human_obj` (i.e., the `Human` class is callable). To make any object in Python callable, Python provides the `__call__` method that needs to be implemented by the object's class. For example, to make `human_obj` object callable, the `Human` class has to implement the `__call__` method. Once the `Human` class implements the `__call__` method, all the objects of the `Human` class can be invoked like functions (i.e., using round parentheses). ``` class Human: def __init__(self, first_name, last_name): print("I am inside __init__ method") self.first_name = first_name self.last_name = last_name def __call__(cls): print("I am inside __call__ method") human_obj = Human("Virat", "Kohli") # Output: I am inside __init__ method # Both human_obj() and human_obj.__call__() are equaivalent human_obj() # Output: I am inside __call__ method human_obj.__call__() # Output: I am inside __call__ method callable(human_obj) # Output: True ``` The above code output shows that after implementing the `__call__` method on the `Human` class,`human_obj` becomes a callable object. We can call the `human_obj` using round parentheses (i.e., `human_obj()`). When we use `human_obj()`, in the background, Python calls the `__call__` method of the `Human` class. So, instead of calling `human_obj` as `human_obj()`, we can directly invoke the `__call__` method on `human_obj` (i.e., `human_obj.__call__()`). Both `human_obj()` and `human_obj.__call__()` are equivalent, and they are the same thing. > For all objects that are callable, their classes must implement the `__call__` method. We know that functions are a callable object, so its class (i.e., `function`) must implement the `__call__` method. Let's invoke the `__call__` method on the `print_function` defined earlier. ``` print_function.__call__() # Output: I am a callable object ``` > In Python, `class` is also a callable object; therefore, it is a `class`'s class (metaclass) (i.e., the `type` class must have a `call` method defined on it). Hence, when we call `Human()`, in the background, Python calls the `call` method of the `type` class. Roughly, the `__call__` method on the `types` class looks something like shown below. This is just for explanation purposes; we will cover the actual definition of the `__call__` method later in the tutorial. ``` class type: def __call__(): # Called when class is called i.e. Human() print("type's call method") ``` With an understanding of `__call__` method and how calling the class calls the `__call__` method of the `type` class, let's find out the answer to the following questions regarding the object initialization process: 1. Who calls the `__new__` and `__init__` method? 2. Who passes the `self` object to the `__init__` method? 3. As the `__init__` method is called after the `__new__` method, and the `__init__` method does not return anything, how does calling the class return the object (i.e., how does calling the `Human` class return the `human_obj` object)? Consider an example of instantiating an object in Python. ``` class Human: def __init__(self, first_name, last_name): self.first_name = first_name self.last_name = last_name human_obj = Human("Virat", "Kohli") ``` We know that when we call the class (i.e., `Human("Virat", "Kohli")`), the `__call__` method of the `type` class is called. However, what is the definition of the `types` class' `__call__` method? As we are talking about CPython, the `type` class' `__call__` method [definition](https://eli.thegreenplace.net/2012/04/16/python-object-creation-sequence) is defined in C language. If we convert it into Python and simplify it, it will look somewhat like this: ``` # type's __call__ method which gets called when Human class is called i.e. Human() def __call__(cls, *args, **kwargs): # cls = Human class # args = ["Virat", "Kohli"] # Calling __new__ method of the Human class, as __new__ method is not defined # on Human, __new__ method of the object class is called human_obj = cls.__new__(*args, **kwargs) # After __new__ method returns the object, __init__ method will only be called if # 1. human_obj is not None # 2. human_obj is an instance of class Human # 3. __init__ method is defined on the Human class if human_obj is not None and isinstance(human_obj, cls) and hasattr(human_obj, '__init__'): # As __init__ is called on human_obj, self will be equal to human_obj in __init__ method human_obj.init(*args, **kwargs) return human_obj ``` Let's understand the above code; when we do `Human("Virat", "Kohli")`, in the background, Python will call the `type` class' `__call__` method, which is defined like the above code snippet. As shown above, the `type` class' `__call__` method accepts `Human` class as the first argument (`cls` is `Human` class), and the remaining arguments are passed while calling the `Human` class. The `type` class' `__call__` method will first call the `__new__` method defined on the `Human` class, if any; otherwise, the `__new__` method of the `Human` class' parent class (i.e. the `object`'s `__new__` method) is called. The `__new__` method will return the `human_obj`. Now, the `__call__` method of the `type` class will call the `__init__` method defined on the `Human` class with `human_obj` as the first argument. `__init__` will initialize the `human_obj` with the passed arguments, and finally, the `__call__` method will return the `human_obj`. ![Object instantiation process in Python](https://www.honeybadger.io/images/blog/posts/python-instantiation-metaclass/object-instantiation-and-creation.png) So, following steps are followed while creating and initializing an object in Python: 1. Call the `Human` class - `Human()`; this internally calls the `__call__` method of the `type` class (i.e., `type.__call__(Human, "Virat", "Kohli")`). 2. `type.__call__` will first call the `__new__` method defined on the `Human` class. If the `__new__` method is not defined on the `Human` class, the `__new__` method of the `object` class will be called. 3. The `__new__` method will the return the object of type `Human` i.e. `human_obj` 4. Now, `type.__call__` will call the `__init__` method defined on the `Human` class with `human_obj` as the first argument. This `human_obj` will be `self` in the `__init__` method. 5. The `__init__` method will initialize the `human_obj` with the `first_name` as `Virat` and the`last_name` as `Kohli`. The `__init__` method will not return anything. 6. In the end, `type.__call__` will return the `human_obj` object. As per the `type.__call__` definition, whenever we create a new object, the `__new__` method will always be called, but calling the `__init__` method depends on the output of the `__new__` method. The `__init__` method will be called only if the `__new__` method returns an object of type `Human` class or a subclass of the `Human` class. Let's understand some of the cases. **Case 1**: If the returned object from the `__new__` method is of type `Human` (i.e., the class of the `__init__` method), the `__init__` method will be called. ``` class Human: def __new__(cls, *args, **kwargs): print(f"Creating the object with cls: {cls} and args: {args}") obj = super().__new__(cls) print(f"Object created with obj: {obj} and type: {type(obj)}") return obj def __init__(self, first_name, last_name): print(f"Started: __init__ method of Human class with self: {self}") self.first_name = first_name self.last_name = last_name print(f"Ended: __init__ method of Human class") human_obj = Human("Virat", "Kohli") ``` Output: ``` # Creating the object with cls: <class '__main__.Human'> and args: ('Virat', 'Kohli') # Object created with obj: <__main__.Human object at 0x102f6a4e0> and type: <class '__main__.Human'> # Started: __init__ method of Human class with self: <__main__.Human object at 0x102f6a400> # Ended: __init__ method of Human class with self: <__main__.Human object at 0x102f6a400> ``` **Case 2**: If the `__new__` method does not return anything, then `__init__` will not be called. ``` class Human: def __new__(cls, *args, **kwargs): print(f"Creating the object with cls: {cls} and args: {args}") obj = super().__new__(cls) print(f"Object created with obj: {obj} and type: {type(obj)}") print("Not returning object from __new__ method, hence __init__ method will not be called") def __init__(self, first_name, last_name): print(f"Started: __init__ method of Human class with self: {self}") self.first_name = first_name self.last_name = last_name print(f"Ended: __init__ method of Human class") human_obj = Human("Virat", "Kohli") ``` Output: ``` # Creating the object with cls: <class '__main__.Human'> and args: ('Virat', 'Kohli') # Object created with obj: <__main__.Human object at 0x102f6a5c0> and type: <class '__main__.Human'> # Not returning object from __new__ method, hence __init__ method will not be called ``` In the above code, the `__new__` method of the `Human` class is called; hence, `obj` of type `Human` is created (i.e., memory is assigned for `obj`). However, as the `__new__` method did not return `human_obj`, the `__init__` method will not be called. Also, `human_obj` will not have the reference for the created object, as it was not returned from the `__new__` method. ``` print(human_obj). # Output: None ``` **Case 3**: The `__new__` method returns an integer object. ``` class Human: def __new__(cls, *args, **kwargs): print(f"Creating the object with cls: {cls} and args: {args}") obj = super().__new__(cls) print(f"Object created with obj: {obj} and type: {type(obj)}") print("Not returning object from __new__ method, hence __init__ method will not be called") return 10 def __init__(self, first_name, last_name): print(f"Started: __init__ method of Human class with self: {self}") self.first_name = first_name self.last_name = last_name print(f"Ended: __init__ method of Human class") human_obj = Human("Virat", "Kohli") ``` In the above code, the `__new__` method of the `Human` class is called; hence, `obj` of type `Human` is created (i.e., memory is assigned for `obj`). However, the `__new__` method did not return `human_obj` but an integer with value `10`, which is not of the `Human` type; hence, the `__init__` method will not be called. Also, `human_obj` will not have the reference for the created object, but it will refer to an integer value of `10`. ``` print(human_obj) # Output: 10 ``` In scenarios where the `__new__` method does not return the instance of the class and we want to initialize the object, we have to call the `__init__` method, explicity, inside the `__new__` method, as shown below: ``` class Human: def __new__(cls, *args, **kwargs): print(f"Creating the object with cls: {cls} and args: {args}") obj = super().__new__(cls) print(f"Object created with obj: {obj} and type: {type(obj)}") print("Not returning object from __new__ method, hence __init__ method will not be called") obj.__init__(*args, **kwargs) return 10 def __init__(self, first_name, last_name): print(f"Started: __init__ method of Human class with self: {self}") self.first_name = first_name self.last_name = last_name print(f"Ended: __init__ method of Human class") human_obj = Human("Virat", "Kohli") ``` Output: ``` # Creating the object with cls: <class '__main__.Human'> and args: ('Virat', 'Kohli') # Object created with obj: <__main__.Human object at 0x102f6a860> and type: <class '__main__.Human'> # Not returning object from __new__ method, hence __init__ method will not be called # Started: __init__ method of Human class with self: <__main__.Human object at 0x102f6a860> # Ended: __init__ method of Human class ``` In the above case, the `__new__` method returned an integer object; hence the `human_obj` value will be 10. ``` print(human_obj) # Output: 10 ``` ## Conclusion In this article, we explored the `__new__`, `__init__`, and `__call__` magic methods and discussed Metaclass in Python. In doing so, we have a better understanding of the object creation and initialization processes in Python. ## References 1. https://eli.thegreenplace.net/2012/04/16/python-object-creation-sequence 2. https://realpython.com/python-metaclasses/\#old-style-vs-new-style-classes 3. https://docs.python.org/3/reference/datamodel.html\#special-method-names ![Rupesh Mishra](https://www-files.honeybadger.io/authors/rupeshmishra.png) Written by [Rupesh Mishra](https://www.honeybadger.io/blog/authors/rupeshmishra/) Rupesh Mishra is a backend developer, freelance blogger, and tutor. He writes about Python, Docker, Kafka, Kubernetes, and MongoDB. When he is not coding he enjoys watching anime and movies. [Back to blog](https://www.honeybadger.io/blog/) ### On this page - [Overview](https://www.honeybadger.io/blog/python-instantiation-metaclass/) - [Table of Contents](https://www.honeybadger.io/blog/python-instantiation-metaclass/#table-of-contents) - [The object base class in Python3](https://www.honeybadger.io/blog/python-instantiation-metaclass/#the-object-base-class-in-python3) - [Objects and types in Python](https://www.honeybadger.io/blog/python-instantiation-metaclass/#objects-and-types-in-python) - [The object instantiation process in Python](https://www.honeybadger.io/blog/python-instantiation-metaclass/#the-object-instantiation-process-in-python) - [The \_\_new\_\_ method](https://www.honeybadger.io/blog/python-instantiation-metaclass/#the-__new__-method) - [The \_\_init\_\_ method](https://www.honeybadger.io/blog/python-instantiation-metaclass/#the-__init__-method) - [The \_\_call\_\_ method](https://www.honeybadger.io/blog/python-instantiation-metaclass/#the-__call__-method) - [Conclusion](https://www.honeybadger.io/blog/python-instantiation-metaclass/#conclusion) - [References](https://www.honeybadger.io/blog/python-instantiation-metaclass/#references) ### Try Honeybadger for FREE Error tracking and performance monitoring in one simple interface. [Start free trial](https://app.honeybadger.io/users/sign_up?plan=team) No credit card required ### Get the Honeybadger Newsletter Join our [community of kick-ass developers](https://www.honeybadger.io/newsletter/) as we learn engineering, DevOps, and cloud architecture. We'll never spam you; we *will* send you cool stuff like exclusive content, memes, and occasional giveaways. ### Get Honeybadger's best Python articles in your inbox We publish 1-2 times per month. Subscribe to get our Python articles as soon as we publish them. We'll never spam you; we *will* send you cool stuff like exclusive content, memes, and occasional giveaways. [![Honeybadger](https://www.honeybadger.io/_astro/bolt.D0BsYe2K_20GiLi.svg) ![Honeybadger](https://www.honeybadger.io/_astro/bolt-dark.DI2bt8qx_20GiLi.svg)](https://www.honeybadger.io/) ### Product - [Error Tracking](https://www.honeybadger.io/tour/error-tracking/) - [Uptime Monitoring](https://www.honeybadger.io/tour/uptime-monitoring/) - [Status Pages](https://www.honeybadger.io/tour/status-pages/) - [Dashboards](https://www.honeybadger.io/tour/dashboards/) - [Logging & Observability](https://www.honeybadger.io/tour/logging-observability/) - [Cron & Heartbeat Monitoring](https://www.honeybadger.io/tour/cron-job-heartbeat-monitoring/) - [Integrations](https://www.honeybadger.io/integrations/) - [Plans & pricing](https://www.honeybadger.io/plans/) - [Compare](https://www.honeybadger.io/vs/) - [Changelog](https://www.honeybadger.io/changelog/) ### Stacks - [Ruby](https://www.honeybadger.io/for/ruby/) - [JavaScript](https://www.honeybadger.io/for/javascript/) - [Python](https://www.honeybadger.io/for/python/) - [Elixir](https://www.honeybadger.io/for/elixir/) - [PHP](https://www.honeybadger.io/for/php/) - [All languages](https://www.honeybadger.io/platforms/) ### Developers - [Get support](https://www.honeybadger.io/contact/) - [Documentation](https://docs.honeybadger.io/) - [Blog](https://www.honeybadger.io/blog/) - [Newsletter](https://www.honeybadger.io/newsletter/) - [Discord](https://www.honeybadger.io/discord/) - [Status](https://status.honeybadger.io/) ### Company - [Meet the 'Badgers](https://www.honeybadger.io/about/) - [Job openings](https://www.honeybadger.io/careers/) - [Contact us](https://www.honeybadger.io/contact/) - [Brand assets](https://www.honeybadger.io/assets/) - [Security & compliance](https://www.honeybadger.io/security/) © 2026 Honeybadger Industries LLC [Terms](https://www.honeybadger.io/terms/) [Privacy](https://www.honeybadger.io/privacy/)
Readable Markdown
In this article, we will cover the object instantiation process followed by Python internally to create objects. I'll start with the fundamentals of object creation, and then we'll dive deep into understanding specific methods, such as `__new__`, `__init__`, and `__call__`. We will also understand the `Metaclass` in Python, along with its role in the object creation process. Although these are advanced topics, the article explains each topic step-by-step and from scratch so that even beginners can understand it. Please note that this article is written with Python3 in mind. ## Table of Contents - [Internals of Object Instantiation and Metaclass in Python](https://www.honeybadger.io/blog/python-instantiation-metaclass/#internals-of-object-instantiation-and-metaclass-in-python) - [Table of Contents](https://www.honeybadger.io/blog/python-instantiation-metaclass/#table-of-contents) - [The `object` base class in Python3](https://www.honeybadger.io/blog/python-instantiation-metaclass/#the-object-base-class-in-python3) - [Objects and types in Python](https://www.honeybadger.io/blog/python-instantiation-metaclass/#objects-and-types-in-python) - [Metaclass in Python](https://www.honeybadger.io/blog/python-instantiation-metaclass/#metaclass-in-python) - [The object instantiation process in Python](https://www.honeybadger.io/blog/python-instantiation-metaclass/#the-object-instantiation-process-in-python) - [The `__new__` method](https://www.honeybadger.io/blog/python-instantiation-metaclass/#the-__new__-method) - [Override the `__new__` method](https://www.honeybadger.io/blog/python-instantiation-metaclass/#override-the-__new__-method) - [The `__init__` method](https://www.honeybadger.io/blog/python-instantiation-metaclass/#the-__init__-method) - [The `__call__` method](https://www.honeybadger.io/blog/python-instantiation-metaclass/#the-__call__-method) - [callable()](https://www.honeybadger.io/blog/python-instantiation-metaclass/#callable) - [Conclusion](https://www.honeybadger.io/blog/python-instantiation-metaclass/#conclusion) - [References](https://www.honeybadger.io/blog/python-instantiation-metaclass/#references) ## The `object` base class in Python3 In Python3, all classes implicitly inherit from the built-in `object` base class. The `object` class provides some common methods, such as `__init__`, `__str__`, and `__new__`, that can be overridden by the child class. Consider the code below, for example: ``` class Human: pass ``` In the above code, the `Human` class does not define any attributes or methods. However, by default, the `Human` class inherits the `object` base class and as a result it has all the attributes and methods defined by the `object` base class. We can check all the attributes and the methods inherited or defined by the `Human` class using the `dir` function. > The `dir` function returns a list of all the attributes and methods defined on any Python object. ``` dir(Human) # Output: ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__'] ``` The `dir` function's output shows that the `Human` class has lots of methods and attributes, most of which are available to the `Human` class from the `object` base class. Python provides a `__bases__` attribute on each class that can be used to obtain a list of classes the given class inherits. > The `__bases__` property of the class contains a list of all the base classes that the given class inherits. ``` print(Human.__bases__) # Output: (<class 'object'>,) ``` The above output shows that the `Human` class has `object` as a base class. We can also look at the attributes and methods defined by the `object` class using the `dir` function. ``` dir(object) # Output: ['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__'] ``` The above definition of the `Human` class is equivalent to the following code; here, we are explicitly inheriting the `object` base class. Although you can explicitly inherit the object base class, it's not required\! ``` class Human(object): pass ``` `object` base class provides `__init__` and `__new__` methods that are used for creating and initializing objects of a class. We will discuss `__init__` and `__new__` in detail in the latter part of the tutorial. ![Object class as the base class in Python](https://www.honeybadger.io/images/blog/posts/python-instantiation-metaclass/inheritance.jpg) *** ## Objects and types in Python Python is an object-oriented programming language. Everything in Python is an object or an instance. Classes, functions, and even simple data types, such as integer and float, are also objects of some class in Python. Each object has a class from which it is instantiated. To get the class or the type of object, Python provides us with the `type` function and `__class__` property defined on the object itself. Let's understand the `type` function with the help of simple data types, such as `int` and `float`. ``` # A simple integer data type a = 9 # The type of a is int (i.e., a is an object of class int) type(a) # Output: <class 'int'> # The type of b is float (i.e., b is an object of the class float) b = 9.0 type(b) # Output: <class 'float'> ``` Unlike other languages, in Python, `9` is an object of class `int`, and it is referred by the variable `a`. Similarly, `9.0` is an object of class `float` and is referred by the variable `b`. > `type` is used to find the type or class of an object. It accepts an object whose type we want to find out as the first argument and returns the type or class of that object. We can also use the `__class__` property of the object to find the type or class of the object. > `__class__` is an attribute on the object that refers to the class from which the object was created. ``` a.__class__ # Output: <class 'int'> b.__class__ # Output: <class 'float'> ``` After simple data types, let's now understand the `type` function and `__class__` attribute with the help of a user-defined class, `Human`. Consider the `Human` class defined below: ``` # Human class definition class Human: pass # Creating a Human object human_obj = Human() ``` The above code creates an instance `human_obj` of the `Human` class. We can find out the class (or type of `human_obj`) from which `human_obj` was created using either the `type` function or the `__class__` property of the `human_obj` object. ``` # human_obj is of type Human type(human_obj) # Output: <class '__main__.Human'> human_obj.__class__ # Output: <class '__main__.Human'> ``` The output of `type(human_obj)` and `human_obj.__class__` shows that `human_obj` is of type `Human` (i.e., `human_obj` has been created from the `Human` class). As functions are also objects in Python, we can find their type or class using the `type` function or the `__class__` attribute. ``` # Check the type of the function def simple_function(): pass type(simple_function) # Output: <class 'function'> simple_function.__class__ # Output: <class 'function'> ``` Thus, `simple_function` is an object of the class `function`. > Classes from which objects are created are also objects in Python. For example, the `Human` class (from which `human_obj` was created) is an object in itself. Yes, you heard it right! Even classes have a class from which they are created or instantiated. Let's find out the type or class of the `Human` class. ``` class Human: pass type(Human) # Output: <class 'type'> Human.__class__ # Output: <class 'type'> ``` Thus, the above code shows that the `Human` class and every other class in Python are objects of the class `type`. This `type` is a class and is different from the `type` function that returns the type of object. The `type` class, from which all the classes are created, is called the `Metaclass` in Python. Let's learn more about metaclass. ### Metaclass in Python > Metaclass is a class from which classes are instantiated or metaclass is a class of a class. Earlier in the article, we checked that variables `a` and `b` are objects of classes `int` and `float`, respectively. As `int` and `float` are classes, they should have a class or metaclass from which they are created. ``` type(int) # Output: <class 'type'> type(float) # Output: <class 'type'> # Even type of object class is - type type(object) # Output: <class 'type'> ``` Thus, the `type` class is the metaclass of `int` and `float` classes. The `type` class is even the metaclass for the built-in `object` class, which is the base class for all the classes in Python. As `type` itself is a class, what is the metaclass of the `type` class? The `type` class is a metaclass of itself\! ``` type(type) # Output: <class 'type'> ``` ![Metaclass in Python](https://www.honeybadger.io/images/blog/posts/python-instantiation-metaclass/metaclass.png) Metaclass is the least talked about topic and is not normally used very much in daily programming. I delve into this topic because metaclass plays an essential role in the object creation process that we will cover later in the article. The two important concepts that we have covered so far are as follows: 1. All classes in Python are objects of the `type` class, and this `type` class is called `Metaclass`. 2. Each class in Python, by default, inherits from the `object` base class. ![Inheritance and metaclass in Python](https://www.honeybadger.io/images/blog/posts/python-instantiation-metaclass/combined.png) *** ## The object instantiation process in Python With a basic understanding of the `Metaclass` and objects in Python, let's now understand the object creation and initialization process in Python. Consider the `Human` class, as defined below: ``` class Human: def __init__(self, first_name, last_name): self.first_name = first_name self.last_name = last_name human_obj = Human("Virat", "Kohli") isinstance(human_obj, Human) # Output: True # As object is the base class for all the class hence # isinstance(human_obj, object) is True isinstance(human_obj, object) # Output: True ``` The output of the above code shows that `human_obj` is an instance of class `Human` with the `first_name` as `Virat` and the `last_name` as `Kohli`. If we look at the above code closely, it's natural to have some questions: 1. Per the definition of the `Human` class, we don't return anything from the `__init__` method; how does calling the `Human` class return the `human_obj`? 2. We know that the `__init__` method is used for initializing the object, but how does the `__init__` method get `self`? In this section, we will discuss each of these questions in detail and answer them. Object creation in Python is a two-step process. In the first step, Python creates the object, and in the second step, it initializes the object. Most of the time, we are only interested in the second step (i.e., the initialization step). Python uses the `__new__` method in the first step (i.e., object creation) and uses the `__init__` method in the second step (i.e., initialization). If the class does not define these methods, they are inherited from the `object` base class. As the `Human` class does not define the `__new__` method, during the object instantiation process, the `__new__` method of the `object`'s class is called, while for initialization, the `__init__` method of the `Human` class is called. Next, we'll cover each of these methods in detail. ## The `__new__` method The `__new__` method is the first step in the object instantiation process. It is a static method on the `object` class and accepts `cls` or the class reference as the first parameter. The remaining arguments(`Virat` and `Kohli`) are passed while calling the class - `Human("Virat", "Kohli")`. The `__new__` method creates an instance of type `cls` (i.e., it allocates memory for the object by invoking the superclass' i.e. `object` class' `__new__` method using `super().__new__(cls)`). It then returns the instance of type `cls`. Usually, it does not do any initialization, as that is the job of the `__init__` method. However, when you override the `__new__` method, you can also use it to initialize the object or modify it as required before returning it. `__new__` method signature ``` # cls - is the mandatory argument. Object returned by the __new__ method is of type cls @staticmethod def __new__(cls[,...]): pass ``` #### Override the `__new__` method We can modify the object creation process by overriding the `__new__` method of the `object` class. Consider the example below: ``` class Human: def __new__(cls, first_name=None): # cls = Human. cls is the class using which the object will be created. # Created object will be of type cls. # We must call the object class' __new__ to allocate memory obj = super().__new__(cls) # This is equivalent to object.__new__(cls) # Modify the object created if first_name: obj.name = first_name else: obj.name = "Virat" print(type(obj)) # Prints: <__main__.Human object at 0x103665668> # return the object return obj # Create an object # __init__ method of `object` class will be called. virat = Human() print(virat.name) # Output: Virat sachin = Human("Sachin") print(sachin.name) # Output: Sachin ``` In the above example, we have overridden the `__new__` method of the `object` class. It accepts the first arguments as `cls` - a class reference to the `Human` class. > The `__new__` method is a special case in Python. Although it's a static method of the `object` class, on overriding it, we do not have to decorate it with the `staticmethod` decorator. Inside the `__new__` method of the `Human` class, we are first calling the `__new__` method of the `object` class using `super().__new__(cls)`. The `object` class' `__new__` method creates and returns the instance of the class, which is passed as an argument to the `__new__` method. Here, as we are passing `cls` (i.e., the `Human` class reference); the `object`'s `__new__` method will return an instance of type `Human`. > We must call the `object` class' `__new__` method inside the overridden `__new__` method to create the object and allocate memory to the object. > > The `__new__` method of the `Human` class modifies the `obj` returned from the `__new__` method of the `object` class and adds the `name` property to it. Thus, all objects created using the `Human` class will have a `name` property. Voila! We have modified the object instantiation process of the `Human` class. Let's consider another example. In this example, we are creating a new class called `Animal` and overriding the `__new__` method. Here, when we are calling the `__new__` method of the `object` class from the `__new__` method of the `Animal` class, instead of passing the `Animal` class reference as an argument to the `__new__` method of the `object` class, we are passing the `Human` class reference. Hence, the object returned from the `__new__` method of the `object` class will be of type `Human` and not `Animal`. As a result, the object returned from calling the `Animal` class (i.e., `Animal()`) will be of type `Human`. ``` class Animal: def __new__(cls): # Passing Human class reference instead of Animal class reference obj = super().__new__(Human) # This is equivalent to object.__new__(Human) print(f"Type of obj: {type(obj)}") # Prints: Type of obj: <class '__main__.Human'> # return the object return obj # Create an object cat = Animal() # Output: # Type of obj: <class '__main__.Human'> type(cat) # Output: <class '__main__.Human'> ``` ## The `__init__` method The `__init__` method is the second step of the object instantiation process in Python. It takes the first argument as an object or instance returned from the `__new__` method. The remaining arguments are the arguments passed while calling the class `(Human("Virat", "Kohli"))`. These arguments are used for initializing the object. The `__init__` method must not return anything. If you try to return anything using the `__init__` method, it will raise an exception, as shown below: ``` class Human: def __init__(self, first_name): self.first_name = first_name return self human_obj = Human('Virat') # Output: TypeError: __init__() should return None, not 'Human' ``` Consider a simple example to understand both the `__new__` and `__init__` method. ``` class Human: def __new__(cls, *args, **kwargs): # Here, the __new__ method of the object class must be called to create # and allocate the memory to the object print("Inside new method") print(f"args arguments {args}") print(f"kwargs arguments {kwargs}") # The code below calls the __new__ method of the object's class. # Object class' __new__ method allocates a memory # for the instance and returns that instance human_obj = super(Human, cls).__new__(cls) print(f"human_obj instance - {human_obj}") return human_obj # As we have overridden the __init__ method, the __init__ method of the object class will not be called def __init__(self, first_name, last_name): print("Inside __init__ method") # self = human_obj returned from the __new__ method self.first_name = first_name self.last_name = last_name print(f"human_obj instance inside __init__ {self}: {self.first_name}, {self.last_name}") human_obj = Human("Virat", "Kohli") # Output # Inside new method # args arguments ('Virat', 'Kohli') # kwargs arguments {} # human_obj instance - <__main__.Human object at 0x103376630> # Inside __init__ method # human_obj instance inside __init__ <__main__.Human object at 0x103376630>: Virat, Kohli ``` In the above code, we have overridden both the `__new__` and `__init__` method of the `object`'s class. `__new__` creates the object (`human_obj`) of type `Human` class and returns it. Once the `__new__` method is complete, Python calls the `__init__` method with the `human_obj` object as the first argument. The `__init__` method initializes the `human_obj` with `first_name` as `Virat` and `last_name` as `Kohli`. As object creation is the first step, and initialization is the second step, the `__new__` method will always be called before the `__init__` method Both `__init__` and `__new__` are called magic methods in Python. Magic methods have names that begin and end with `__` (double underscores or "dunder"). Magic methods are called implicitly by the Python; you do not have to call them explicitly. For example, both the `__new__` and `__init__` method are called implicitly by Python. Let's cover one more magic method, `__call__`. ## The `__call__` method The `__call__` method is a magic method in Python that is used to make the objects callable. Callable objects are objects that can be called. For example, `functions` are callable objects, as they can be called using the round parenthesis. Consider an example to better understand callable objects: ``` def print_function(): print("I am a callable object") # print_function is callable as it can be called using round parentheses print_function() # Output # I am a callable object ``` Let's try to call an `integer` object. As `integer` objects are not callable, calling them will raise an exception. ``` a = 10 # As the integer object is not callable, calling `a` using round parentheses will raise an exception. a() # Output: TypeError: 'int' object is not callable ``` ### callable() The `callable` function is used to determine whether an object is callable. The `callable` function takes the object reference as an argument and returns `True` if the object appears to be callable or `False` if the object is not callable. If the `callable` function returns `True`, the object might not be callable; however, if it returns `False`, then the object is certainly not callable. ``` # Functions are callable callable(print_function) # Output: True # Interger object is not callable callable(a) # Output: False ``` Let's determine whether the classes in Python are callable. Here, we will determine whether the `Human` class defined earlier is callable. ``` callable(Human) # Output: True ``` Yes, classes in Python are callable, and they should be! Don't you think so? When we call the class, it returns the instance of that class. Let's find out whether the objects created from the class are callable. ``` human_obj = Human("Virat", "Kohli") callable(human_obj) # Output: False # Let's try calling the human_obj human_obj() # As human_obj is not callable it raises an exception # Output: TypeError: 'Human' object is not callable ``` So, `human_obj` is not callable though the class of `human_obj` (i.e., the `Human` class is callable). To make any object in Python callable, Python provides the `__call__` method that needs to be implemented by the object's class. For example, to make `human_obj` object callable, the `Human` class has to implement the `__call__` method. Once the `Human` class implements the `__call__` method, all the objects of the `Human` class can be invoked like functions (i.e., using round parentheses). ``` class Human: def __init__(self, first_name, last_name): print("I am inside __init__ method") self.first_name = first_name self.last_name = last_name def __call__(cls): print("I am inside __call__ method") human_obj = Human("Virat", "Kohli") # Output: I am inside __init__ method # Both human_obj() and human_obj.__call__() are equaivalent human_obj() # Output: I am inside __call__ method human_obj.__call__() # Output: I am inside __call__ method callable(human_obj) # Output: True ``` The above code output shows that after implementing the `__call__` method on the `Human` class,`human_obj` becomes a callable object. We can call the `human_obj` using round parentheses (i.e., `human_obj()`). When we use `human_obj()`, in the background, Python calls the `__call__` method of the `Human` class. So, instead of calling `human_obj` as `human_obj()`, we can directly invoke the `__call__` method on `human_obj` (i.e., `human_obj.__call__()`). Both `human_obj()` and `human_obj.__call__()` are equivalent, and they are the same thing. > For all objects that are callable, their classes must implement the `__call__` method. We know that functions are a callable object, so its class (i.e., `function`) must implement the `__call__` method. Let's invoke the `__call__` method on the `print_function` defined earlier. ``` print_function.__call__() # Output: I am a callable object ``` > In Python, `class` is also a callable object; therefore, it is a `class`'s class (metaclass) (i.e., the `type` class must have a `call` method defined on it). Hence, when we call `Human()`, in the background, Python calls the `call` method of the `type` class. Roughly, the `__call__` method on the `types` class looks something like shown below. This is just for explanation purposes; we will cover the actual definition of the `__call__` method later in the tutorial. ``` class type: def __call__(): # Called when class is called i.e. Human() print("type's call method") ``` With an understanding of `__call__` method and how calling the class calls the `__call__` method of the `type` class, let's find out the answer to the following questions regarding the object initialization process: 1. Who calls the `__new__` and `__init__` method? 2. Who passes the `self` object to the `__init__` method? 3. As the `__init__` method is called after the `__new__` method, and the `__init__` method does not return anything, how does calling the class return the object (i.e., how does calling the `Human` class return the `human_obj` object)? Consider an example of instantiating an object in Python. ``` class Human: def __init__(self, first_name, last_name): self.first_name = first_name self.last_name = last_name human_obj = Human("Virat", "Kohli") ``` We know that when we call the class (i.e., `Human("Virat", "Kohli")`), the `__call__` method of the `type` class is called. However, what is the definition of the `types` class' `__call__` method? As we are talking about CPython, the `type` class' `__call__` method [definition](https://eli.thegreenplace.net/2012/04/16/python-object-creation-sequence) is defined in C language. If we convert it into Python and simplify it, it will look somewhat like this: ``` # type's __call__ method which gets called when Human class is called i.e. Human() def __call__(cls, *args, **kwargs): # cls = Human class # args = ["Virat", "Kohli"] # Calling __new__ method of the Human class, as __new__ method is not defined # on Human, __new__ method of the object class is called human_obj = cls.__new__(*args, **kwargs) # After __new__ method returns the object, __init__ method will only be called if # 1. human_obj is not None # 2. human_obj is an instance of class Human # 3. __init__ method is defined on the Human class if human_obj is not None and isinstance(human_obj, cls) and hasattr(human_obj, '__init__'): # As __init__ is called on human_obj, self will be equal to human_obj in __init__ method human_obj.init(*args, **kwargs) return human_obj ``` Let's understand the above code; when we do `Human("Virat", "Kohli")`, in the background, Python will call the `type` class' `__call__` method, which is defined like the above code snippet. As shown above, the `type` class' `__call__` method accepts `Human` class as the first argument (`cls` is `Human` class), and the remaining arguments are passed while calling the `Human` class. The `type` class' `__call__` method will first call the `__new__` method defined on the `Human` class, if any; otherwise, the `__new__` method of the `Human` class' parent class (i.e. the `object`'s `__new__` method) is called. The `__new__` method will return the `human_obj`. Now, the `__call__` method of the `type` class will call the `__init__` method defined on the `Human` class with `human_obj` as the first argument. `__init__` will initialize the `human_obj` with the passed arguments, and finally, the `__call__` method will return the `human_obj`. ![Object instantiation process in Python](https://www.honeybadger.io/images/blog/posts/python-instantiation-metaclass/object-instantiation-and-creation.png) So, following steps are followed while creating and initializing an object in Python: 1. Call the `Human` class - `Human()`; this internally calls the `__call__` method of the `type` class (i.e., `type.__call__(Human, "Virat", "Kohli")`). 2. `type.__call__` will first call the `__new__` method defined on the `Human` class. If the `__new__` method is not defined on the `Human` class, the `__new__` method of the `object` class will be called. 3. The `__new__` method will the return the object of type `Human` i.e. `human_obj` 4. Now, `type.__call__` will call the `__init__` method defined on the `Human` class with `human_obj` as the first argument. This `human_obj` will be `self` in the `__init__` method. 5. The `__init__` method will initialize the `human_obj` with the `first_name` as `Virat` and the`last_name` as `Kohli`. The `__init__` method will not return anything. 6. In the end, `type.__call__` will return the `human_obj` object. As per the `type.__call__` definition, whenever we create a new object, the `__new__` method will always be called, but calling the `__init__` method depends on the output of the `__new__` method. The `__init__` method will be called only if the `__new__` method returns an object of type `Human` class or a subclass of the `Human` class. Let's understand some of the cases. **Case 1**: If the returned object from the `__new__` method is of type `Human` (i.e., the class of the `__init__` method), the `__init__` method will be called. ``` class Human: def __new__(cls, *args, **kwargs): print(f"Creating the object with cls: {cls} and args: {args}") obj = super().__new__(cls) print(f"Object created with obj: {obj} and type: {type(obj)}") return obj def __init__(self, first_name, last_name): print(f"Started: __init__ method of Human class with self: {self}") self.first_name = first_name self.last_name = last_name print(f"Ended: __init__ method of Human class") human_obj = Human("Virat", "Kohli") ``` Output: ``` # Creating the object with cls: <class '__main__.Human'> and args: ('Virat', 'Kohli') # Object created with obj: <__main__.Human object at 0x102f6a4e0> and type: <class '__main__.Human'> # Started: __init__ method of Human class with self: <__main__.Human object at 0x102f6a400> # Ended: __init__ method of Human class with self: <__main__.Human object at 0x102f6a400> ``` **Case 2**: If the `__new__` method does not return anything, then `__init__` will not be called. ``` class Human: def __new__(cls, *args, **kwargs): print(f"Creating the object with cls: {cls} and args: {args}") obj = super().__new__(cls) print(f"Object created with obj: {obj} and type: {type(obj)}") print("Not returning object from __new__ method, hence __init__ method will not be called") def __init__(self, first_name, last_name): print(f"Started: __init__ method of Human class with self: {self}") self.first_name = first_name self.last_name = last_name print(f"Ended: __init__ method of Human class") human_obj = Human("Virat", "Kohli") ``` Output: ``` # Creating the object with cls: <class '__main__.Human'> and args: ('Virat', 'Kohli') # Object created with obj: <__main__.Human object at 0x102f6a5c0> and type: <class '__main__.Human'> # Not returning object from __new__ method, hence __init__ method will not be called ``` In the above code, the `__new__` method of the `Human` class is called; hence, `obj` of type `Human` is created (i.e., memory is assigned for `obj`). However, as the `__new__` method did not return `human_obj`, the `__init__` method will not be called. Also, `human_obj` will not have the reference for the created object, as it was not returned from the `__new__` method. ``` print(human_obj). # Output: None ``` **Case 3**: The `__new__` method returns an integer object. ``` class Human: def __new__(cls, *args, **kwargs): print(f"Creating the object with cls: {cls} and args: {args}") obj = super().__new__(cls) print(f"Object created with obj: {obj} and type: {type(obj)}") print("Not returning object from __new__ method, hence __init__ method will not be called") return 10 def __init__(self, first_name, last_name): print(f"Started: __init__ method of Human class with self: {self}") self.first_name = first_name self.last_name = last_name print(f"Ended: __init__ method of Human class") human_obj = Human("Virat", "Kohli") ``` In the above code, the `__new__` method of the `Human` class is called; hence, `obj` of type `Human` is created (i.e., memory is assigned for `obj`). However, the `__new__` method did not return `human_obj` but an integer with value `10`, which is not of the `Human` type; hence, the `__init__` method will not be called. Also, `human_obj` will not have the reference for the created object, but it will refer to an integer value of `10`. ``` print(human_obj) # Output: 10 ``` In scenarios where the `__new__` method does not return the instance of the class and we want to initialize the object, we have to call the `__init__` method, explicity, inside the `__new__` method, as shown below: ``` class Human: def __new__(cls, *args, **kwargs): print(f"Creating the object with cls: {cls} and args: {args}") obj = super().__new__(cls) print(f"Object created with obj: {obj} and type: {type(obj)}") print("Not returning object from __new__ method, hence __init__ method will not be called") obj.__init__(*args, **kwargs) return 10 def __init__(self, first_name, last_name): print(f"Started: __init__ method of Human class with self: {self}") self.first_name = first_name self.last_name = last_name print(f"Ended: __init__ method of Human class") human_obj = Human("Virat", "Kohli") ``` Output: ``` # Creating the object with cls: <class '__main__.Human'> and args: ('Virat', 'Kohli') # Object created with obj: <__main__.Human object at 0x102f6a860> and type: <class '__main__.Human'> # Not returning object from __new__ method, hence __init__ method will not be called # Started: __init__ method of Human class with self: <__main__.Human object at 0x102f6a860> # Ended: __init__ method of Human class ``` In the above case, the `__new__` method returned an integer object; hence the `human_obj` value will be 10. ``` print(human_obj) # Output: 10 ``` ## Conclusion In this article, we explored the `__new__`, `__init__`, and `__call__` magic methods and discussed Metaclass in Python. In doing so, we have a better understanding of the object creation and initialization processes in Python. ## References 1. https://eli.thegreenplace.net/2012/04/16/python-object-creation-sequence 2. https://realpython.com/python-metaclasses/\#old-style-vs-new-style-classes 3. https://docs.python.org/3/reference/datamodel.html\#special-method-names
Shard197 (laksa)
Root Hash15249212189560886397
Unparsed URLio,honeybadger!www,/blog/python-instantiation-metaclass/ s443