On Sun, 06 Oct 2013 20:17:33 +0200, Marco Buttu wrote: > Hi all, I have a question about class creation and the __call__ method. > I have the following metaclass: > > >>> class FooMeta(type): > ... def __call__(metacls, name, bases, namespace): > ... print("FooMeta.__call__()")
At this point, FooMeta is nothing special, it's just an ordinary class. Calling it "FooMeta" doesn't make it special. Like every ordinary class, __call__ will only be called when an *instance* is called. Since you have no FooMeta instances yet, FooMeta.__call__ won't be called. > From what I undestood, at the end of the class statement happens > something like this: > > >>> def __call__(metacls, name, bases, namespace): > ... print("FooMeta.__call__()") > ... > >>> FooMeta = type('FooMeta', (type,), {'__call__': __call__}) You're referring to the class statement ("class FooMeta(type): ...") being syntactic sugar for the above direct call to type. Correct. Again, this applies to *all* classes, not just metaclasses. > The call to the metaclass type causes the call to type.__call__(), so > that's happened is: > > >>> FooMeta = type.__call__(type, 'FooMeta', (type,), {'__call__': > __call__}) Yes but no... 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", not in the sense you mean. You don't have a "metaclass type" yet, except for type itself. You have a class *called* FooMeta, but it hasn't been called. It can't be called yet, because it hasn't yet been created! You're still executing the "class FooMeta..." statement, creating FooMeta. So at the point FooMeta is created, the only metaclass involved is type itself. Hence, it is only type.__call__ which is involved, not FooMeta.__call__. FooMeta.__call__ is used when you call an instance of FooMeta: class Foo(metaclass=FooMeta): ... obj = Foo() Here, Foo is an instance of FooMeta, so calling Foo calls FooMeta.__call__. What I think you are looking for is FooMeta.__new__, which gets called when the instance is created. What's the instance of FooMeta again? It's class Foo. So at the end of "class Foo(metaclass=FooMeta)..." the FooMeta.__new__ method is called to create Foo. Then, once Foo is created, instantiating it using "obj = Foo()" calls FooMeta.__call__. > Now I expected the output `FooMeta.__call__()` from the following Foo > class creation: > > >>> class Foo(metaclass=FooMeta): > ... pass No, not at the class creation. Metaclass.__new__ is called when you create an instance; the instance here is class Foo, so FooMeta.__new__ will be called. > because I thought at the end of the class Foo suite this should have > been happened: > > >>> Foo = FooMeta.__call__(FooMeta, 'Foo', (), {}) > FooMeta.__call__() Go back to the rule for class creation: class Spam(bases): <namespace> is syntactic sugar for: type('Spam', bases, namespace) used to instantiate the new instance, Spam. If a metaclass is given, it is used instead of type. So you'll have: Meta('Spam', bases, namespace) and Meta.__new__ will be called to create the instance. Note: you don't need to use a *class* as metaclass! Bizarre but true: any callable object will do, so long as it matches the expected signature. Watch this: py> class Wot(metaclass=lambda name, bases, namespace: 42): ... a = 12 ... def __len__(self): ... return 9999 ... py> Wot 42 But I digress. In your case, you are using a subclass of type as your metaclass, and it is creating a new instance of FooMeta. When a new instance is created, FooMeta.__new__ is called. To get the effect you are after, you can: 1) Use FooMeta.__new__ instead of __call__; 2) Use a metaclass of the metaclass, FooMetaMeta.__call__; or 3) Use a function that takes the same signature as type. -- Steven -- https://mail.python.org/mailman/listinfo/python-list