Posted on 16 Aug 2022, this text provides information on Bugs & Fixes related to General Tech. Please note that while accuracy is prioritized, the data presented might not be entirely correct or up-to-date. This information is offered for general knowledge and informational purposes only, and should not be considered as a substitute for professional advice.
Role of a metaclass' __call__() method when creating a class instance
If you've done Python programming for more than a few months you'll eventually stumble upon code that looks like this:
# define a classclassSomeClass(object):# ...# some definition here ...# ...# create an instance of it
instance =SomeClass()# then call the object as if it's a function
result = instance('foo','bar')
The latter is possible when you implement the __call__() magic method on the class.
classSomeClass(object):# ...# some definition here ...# ...def __call__(self, foo, bar):return bar + foo
The __call__() method is invoked when an instance of a class is used as a callable. But as we've seen from previous answers a class itself is an instance of a metaclass, so when we use the class as a callable (i.e. when we create an instance of it) we're actually calling its metaclass' __call__() method. At this point most Python programmers are a bit confused because they've been told that when creating an instance like this instance = SomeClass() you're calling its __init__() method. Some who've dug a bit deeper know that before __init__() there's __new__(). Well, today another layer of truth is being revealed, before __new__() there's the metaclass' __call__().
Let's study the method call chain from specifically the perspective of creating an instance of a class.
This is a metaclass that logs exactly the moment before an instance is created and the moment it's about to return it.
classMeta_1(type):def __call__(cls):print"Meta_1.__call__() before creating an instance of ", cls
instance = super(Meta_1, cls).__call__()print"Meta_1.__call__() about to return instance."return instance
classClass_1(object):
__metaclass__ =Meta_1def __new__(cls):print"Class_1.__new__() before creating an instance."
instance = super(Class_1, cls).__new__(cls)print"Class_1.__new__() about to return instance."return instance
def __init__(self):print"entering Class_1.__init__() for instance initialization."
super(Class_1,self).__init__()print"exiting Class_1.__init__()."
And now let's create an instance of Class_1
instance =Class_1()# Meta_1.__call__() before creating an instance of .# Class_1.__new__() before creating an instance.# Class_1.__new__() about to return instance.# entering Class_1.__init__() for instance initialization.# exiting Class_1.__init__().# Meta_1.__call__() about to return instance.
Observe that the code above doesn't actually do anything more than logging the tasks. Each method delegates the actual work to its parent's implementation, thus keeping the default behavior. Since type is Meta_1's parent class (type being the default parent metaclass) and considering the ordering sequence of the output above, we now have a clue as to what would be the pseudo implementation of type.__call__():
classtype:def __call__(cls,*args,**kwarg):# ... maybe a few things done to cls here# then we call __new__() on the class to create an instance
instance = cls.__new__(cls,*args,**kwargs)# ... maybe a few things done to the instance here# then we initialize the instance with its __init__() method
instance.__init__(*args,**kwargs)# ... maybe a few more things done to instance here
Role of a metaclass' __call__() method when creating a class instance
If you've done Python programming for more than a few months you'll eventually stumble upon code that looks like this:
# define a classclassSomeClass(object):# ...# some definition here ...# ...# create an instance of it
instance =SomeClass()# then call the object as if it's a function
result = instance('foo','bar')
The latter is possible when you implement the __call__() magic method on the class.
classSomeClass(object):# ...# some definition here ...# ...def __call__(self, foo, bar):return bar + foo
The __call__() method is invoked when an instance of a class is used as a callable. But as we've seen from previous answers a class itself is an instance of a metaclass, so when we use the class as a callable (i.e. when we create an instance of it) we're actually calling its metaclass' __call__() method. At this point most Python programmers are a bit confused because they've been told that when creating an instance like this instance = SomeClass() you're calling its __init__() method. Some who've dug a bit deeper know that before __init__() there's __new__(). Well, today another layer of truth is being revealed, before __new__() there's the metaclass' __call__().
Let's study the method call chain from specifically the perspective of creating an instance of a class.
This is a metaclass that logs exactly the moment before an instance is created and the moment it's about to return it.
classMeta_1(type):def __call__(cls):print"Meta_1.__call__() before creating an instance of ", cls
instance = super(Meta_1, cls).__call__()print"Meta_1.__call__() about to return instance."return instance
This is a class that uses that metaclass
classClass_1(object):
__metaclass__ =Meta_1def __new__(cls):print"Class_1.__new__() before creating an instance."
instance = super(Class_1, cls).__new__(cls)print"Class_1.__new__() about to return instance."return instance
def __init__(self):print"entering Class_1.__init__() for instance initialization."
super(Class_1,self).__init__()print"exiting Class_1.__init__()."
And now let's create an instance of Class_1
instance =Class_1()# Meta_1.__call__() before creating an instance of .# Class_1.__new__() before creating an instance.# Class_1.__new__() about to return instance.# entering Class_1.__init__() for instance initialization.# exiting Class_1.__init__().# Meta_1.__call__() about to return instance.
Observe that the code above doesn't actually do anything more than logging the tasks. Each method delegates the actual work to its parent's implementation, thus keeping the default behavior. Since type is Meta_1's parent class (type being the default parent metaclass) and considering the ordering sequence of the output above, we now have a clue as to what would be the pseudo implementation of type.__call__():
class type:def __call__(cls,*args,**kwarg):# ... maybe a few things done to cls here# then we call __new__() on the class to create an instance
instance = cls.__new__(cls,*args,**kwargs)# ... maybe a few things done to the instance here# then we initialize the instance with its __init__() method
instance.__init__(*args,**kwargs)# ... maybe a few more things done to instance here
No matter what stage you're at in your education or career, TuteeHUB will help you reach the next level that
you're aiming for. Simply,Choose a subject/topic and get started in self-paced practice
sessions to improve your knowledge and scores.
manpreet
Best Answer
2 years ago
What are metaclasses and what do we use them for?