10

From my understanding the __call__ method inside a class implements the function call operator, for example:

class Foo:
    def __init__(self):
        print("I'm inside the __init__ method")

    def __call__(self):
        print("I'm inside the __call__ method")

x = Foo() #outputs "I'm inside the __init__ method"
x() #outputs "I'm inside the __call__ method"

However, I'm going through the Python Cookbook and the writer defined a metaclass to control instance creation so that you can't instantiate an object directly. This is how he did it:

class NoInstance(type):
    def __call__(self, *args, **kwargs):
        raise TypeError("Can't instantaite class directly")


class Spam(metaclass=NoInstance):
    @staticmethod
    def grok(x):
        print("Spam.grok")

Spam.grok(42) #outputs "Spam.grok"

s = Spam() #outputs TypeError: Can't instantaite class directly

However, what I don't get is how s() wasn't called, yet it's __call__ method was called. How does this work?

MSeifert
  • 145,886
  • 38
  • 333
  • 352
electro7912
  • 339
  • 4
  • 14

2 Answers2

10

Metaclasses implement how the class will behave (not the instance). So when you look at the instance creation:

x = Foo()

This literally "calls" the class Foo. That's why __call__ of the metaclass is invoked before the __new__ and __init__ methods of your class initialize the instance.


As @Take_Care_ pointed out in the comments one great ressource on metaclasses is ionelmc's blog post about "Understanding Python metaclasses". One image in that blog post directly applies to your situation:

enter image description here

The image is directly copied from the blog post.

MSeifert
  • 145,886
  • 38
  • 333
  • 352
  • 1
    great and simple answer ! . If OP wants something more : https://blog.ionelmc.ro/2015/02/09/understanding-python-metaclasses/ – Take_Care_ Aug 06 '17 at 21:10
  • 1
    Thanks. This is exactly what i was looking for ! – electro7912 Aug 06 '17 at 21:29
  • This makes it seem magical. Also read Ignacio's simple answer below and read it again until this answer (and included diagram) no longer seems magical. (After you do, you will realize that implementation of `type.__call__` *is* actually magical - it acts differently depending on its first argument / caller!) – BadZen Aug 27 '23 at 16:57
3

A class is simply an instance of its metaclass. Since the metaclass defines __call__(), calling the instance of the metaclass, i.e. the class, as a function, i.e. as a constructor, will invoke it.

Ignacio Vazquez-Abrams
  • 776,304
  • 153
  • 1,341
  • 1,358