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