views:

95

answers:

1

Here is a python session.

>>> class Z(type):
    def __new__(cls, name, bases, attrs):
        print cls
        print name
        return type(name, bases, attrs)
...     
>>> class Y(object):
    __metaclass__ = Z
...     
<class '__main__.Z'>
Y
>>> class X(Y):
...     pass
... 
>>> class W(Y):
...     __metaclass__ = Z
...     
<class '__main__.Z'>
W
>>>

After I define class X I expect Z._new__ to be called for it, and to print the two line, which is not happening, (as metaclass are inherited?)

+4  A: 

The problem is that the cls argument (which is the metaclass object) is not passed on when you call type, therefore the class object Y that is created and returned does not have any reference to the metaclass Z.

If you replace the last line in __new__ with

return super(Z, cls).__new__(cls, name, bases, attrs)

then it works. Note that even though cls is used in super we still have to provide cls as an argument as well, since super here returns an unbound method (see here for more).

As an alternative to using super one could use:

 return type.__new__(cls, name, bases, attrs)

The important thing is that we give cls (our metaclass object Z) to the classmethod __new__. The shorter form type(name, bases, attrs) fills in type itself for the cls argument, which is of course wrong. This error is similar to calling an instance method with the wrong self argument.

I prefer using super, since this is better style.

nikow
Ah, ok, that work. But shouldnt `return super(Z, cls).__new__` be equivalent to `type.__class__.new` whis is equivalent to `type.__new__` which should be same as creating a new class via `type`?
uswaretech
It is actually not the same, I now address this in my answer. Super does call the `type.__new__` method, but we can then use the correct `cls` argument, which is not possible if we just call `type` directly.
nikow