5

From all I understand about Python object oriented programming if a class has __call__ method defined that would be invoked if we use the instance of the class like a function call. For example:

class Employee:
    def __init__(self,name,sal):
        self.name = name
        self.salary = sal
    def __call__(self,value):
        return self.salary * value

e = Employee("Subhayan",20000)
print (e(10))

So the __call__ method takes the object instance as the first argument.

I am just trying to understand metaclasses in Python and I read that type is the default metaclass of all user defined classes.

If I define a basic custom metaclass in Python:

class Meta(type):
    def __new__(meta, classname, supers, classdict):
        # Run by inherited type.__call__
        return type.__new__(meta, classname, supers, classdict)

Now as per the documentation given in the book the metaclass __new__ method would be run by the __call__ method inherited from type.

Now my question is to use the __call__ method of any class we have to have an object of that class and then call it as a function.

Here we don't have any object of type to use its __call__ function.

Can someone please explain to me how is the __call__ function of type class coming into picture?

martineau
  • 119,623
  • 25
  • 170
  • 301
Subhayan Bhattacharya
  • 5,407
  • 7
  • 42
  • 60

2 Answers2

6

Any class is itself an instance of type "type" - therefore "calling" a class just calls the method __call__ on its class - which happens to be type's __call__. The effect of type.__call__ is exactly: on code like:

class A:
    pass
b = A()
  1. type.__call__ receives the class A itself as its first parameter.
  2. It calls the A.__new__ - in pseudocode we could write instace = A.__new__(cls) as what runs.
  3. That returns an instance of the "A" class
  4. Then it calls __init__ on the instance(instance.__init__())
  5. ...and returns that instance return instance

However, if the the class itself is derived from "type" - i.e., it is the instantiation of a "new" class, extra steps are taken: The special value of the magic __class__ variable is filled in any of the class methods - if any of those methods use a call to super. And on Python 3.6, these 2 further steps: any of the class attributes that define a __set_name__ method are called, and the class's __init_subclass__ method is called.

jsbueno
  • 99,910
  • 10
  • 151
  • 209
  • I will open a new question since i am still not clear when the class is itself derived from type. I will paste a new code there, so please help me with that as well. – Subhayan Bhattacharya May 26 '17 at 06:43
  • Also until a class is created it is not an instance of type yet. So when in the above code A() is called then i can understand the __call__ method of type getting invoked. But __new__ should get called as soon as the class statement in run. But as you mentioned __new__ is getting called from __call__. Not sure if i understand correctly. – Subhayan Bhattacharya May 26 '17 at 07:52
2

Remember, type is a metaclass so it's instances are classes, not objects. Than means (among other things) that when you do this:

e= Employee(*args,**kwargs)

You are calling Employee.__init__ and some methods from your metaclass including Meta.__call__, the same way that when you do .

print (e(10))

you are invoking your custom __call__ method.

Take for example this Singleton metaclass:

class Singleton(type):
    _instances = {}
    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
        return cls._instances[cls]

class MyClass(BaseClass):
    __metaclass__ = Singleton

Now every time you create a new instance of MyClass, the __call__ method in the metaclass is called before the actual instance is created allowing you to check if a previous one exists and return that instead.

Hope this helps.

yorodm
  • 4,359
  • 24
  • 32
  • One question here. Inside Singleton __call__ function the cls argument would have the value of MyClass. And _instances belongs to the Singleton class .How can then MyClass have the _instances dictionary? – Subhayan Bhattacharya May 26 '17 at 09:20
  • Because `MyClass` is an instance of `Singleton`. – yorodm May 26 '17 at 11:15
  • Subhayan: ...and all `Singleton` instances share the same `_instances` dictionary since it's a class, _not_ an instance, attribute. – martineau Feb 26 '18 at 19:01