Overriding of the type.__call__() method in a metaclass

Marco Buttu marco.buttu at gmail.com
Mon Oct 7 01:22:02 EDT 2013


On 10/07/2013 04:27 AM, Steven D'Aprano wrote:

> On Sun, 06 Oct 2013 20:17:33 +0200, Marco Buttu wrote:
>> >
>> >  >>> class FooMeta(type):
>> >...     def __call__(metacls, name, bases, namespace):
>> >...        print("FooMeta.__call__()")
...
>> >  From what I undestood, at the end of the class statement...
>> >
>> >  >>> def __call__(metacls, name, bases, namespace):
>> >...     print("FooMeta.__call__()")
>> >...
>> >  >>> FooMeta = type('FooMeta', (type,), {'__call__': __call__})
>
> Your code snippet is correct. The "class FooMeta(type)..." statement is
> syntactic sugar for type.__call__(...). But your description is
> incorrect. This doesn't occur when you "call the metaclass type"...

Oh damn! Your are right :) Thanks to you and Peter. Now (I hope...) it 
should be clear for me:

 >>> class FooMeta(type):
...     def __call__(meta, name, bases, namespace):
...         print('FooMeta.__call__()')
...
 >>> class InstanceOfFooMeta(type, metaclass=FooMeta):
...     pass
...
 >>> class Foo(metaclass=InstanceOfFooMeta):
...     pass
...
FooMeta.__call__()

I try to summarize the execution flow. The metaclass type creates FooMeta:

 >>> class FooMeta(type):
...     def __call__(meta, name, bases, namespace):
...         print('FooMeta.__call__()')
...

This means at the end of the suite:

     FooMeta = type('FooMeta', (type,), {...})

So Python calls type. But type is an instance of type itself, so:

     FooMeta = type.__call__(type, 'FooMeta', (type,), {...})

At this point FooMeta is created. The next step is:

 >>> class InstanceOfFooMeta(type, metaclass=FooMeta):
...     pass

This causes:

     InstanceOfFooMeta= FooMeta('InstanceOfFooMeta', (type,), {...})

Python is calling FooMeta, so it is calling an instance of type, so the 
code above becomes:

     InstanceOfFooMeta = type.__call__(FooMeta, 'InstanceOfMeta', \
         (type,), {...})


Finally:

 >>> class Foo(metaclass=InstanceOfFooMeta):
...     pass
...
FooMeta.__call__()

In fact at the end of the suite of the class statement, Python calls an 
instance of FooMeta:

     Foo = InstanceOfFooMeta('Foo', (), {...})

so, definitively:

     Foo = FooMeta.__call__(InstanceOfFooMeta, 'Foo', (), {...})

Foo is None, but never mind. I just wanted to clarify me the class 
creation process.
Thanks again and congratulations for your PEP, it is written very very well

-- 
Marco Buttu



More information about the Python-list mailing list