Metaclass mystery

Carl Banks pavlovevidence at gmail.com
Sat May 30 21:15:30 EDT 2009


On May 30, 5:32 pm, LittleGrasshopper <seattleha... at yahoo.com> wrote:
> On May 30, 4:01 pm, LittleGrasshopper <seattleha... at yahoo.com> wrote:
>
>
>
> > I am experimenting with metaclasses, trying to figure out how things
> > are put together. At the moment I am baffled by the output of the
> > following code:
>
> > ************************************
> > """
> > Output is:
>
> > instance of metaclass MyMeta being created
> > (<class '__main__.MyMeta'>, <class '__main__.MyMeta'>)
> > instance of metaclass MyNewMeta being created
> > instance of metaclass MyMeta being created   <<<< Why this?
> > (<class '__main__.MyMeta'>, <class '__main__.MyNewMeta'>)
>
> > """
>
> > class MyMeta(type):
> >     def __new__(meta, classname, bases, classDict):
> >         print 'instance of metaclass MyMeta being created'
> >         return type.__new__(meta, classname, bases, classDict)
>
> > class MyNewMeta(type):
> >     def __new__(meta, classname, bases, classDict):
> >         print 'instance of metaclass MyNewMeta being created'
> >         return type(classname, bases, classDict)
>
> > """
> > Notice that a metaclass can be a factory function:
> > def f(classname, bases, classDict):
> >     return type(classname, bases, classDict)
>
> > class MyClass(object):
> >     __metaclass__ = f
> > """
>
> > class MyClass(object):
> >     __metaclass__ = MyMeta
>
> > print (MyClass.__class__, MyClass.__metaclass__)
>
> > class MySubClass(MyClass):
> >     __metaclass__ = MyNewMeta
>
> > print (MySubClass.__class__, MySubClass.__metaclass__)
> > ************************************
> > Honestly, I don't know why this line:
> > instance of metaclass MyMeta being created   <<<< Why this?
> > is being output when the MySubClass class object is instantiated.
> > MyNewMeta's __new__ method simply instantiates type directly (which I
> > know shouldn't be done, but I'm just experimenting and trying to
> > understand the code's output.)
>
> > I would really appreciate some ideas.
>
> This is my working theory:
>
> return type(classname, bases, classDict), in MyNewMeta.__new__(),
> actually calls type.__new__(type, classname, bases, classDict). I
> think the magic happens in this method call. This method must look at
> bases and notice that MySubClass extends MyClass, and that MyClass'
> type is MyMeta, so instead of instantiating a 'type' object it decides
> to instantiate a 'MyMeta' object, which accounts for the output.

That's correct.  A type's metaclass has to be a not-necessarily proper
superclass of the all the bases' metaclasses.

Whenever possible type() will figure the most derived metaclass of all
the bases and use that as the metaclass, but sometimes it can't be
done.  Consider the following:


class AMeta(type):
    pass

class A(object):
    __metaclass__ = AMeta

class BMeta(type):
    pass

class B(object):
    __metaclass__ = BMeta

class C(A,B):
    pass  # this will raise exception

class CMeta(AMeta,BMeta):
    pass

class C(A,B):
    __metaclass__ = CMeta # this will work ok



> Seriously, metaclasses are making my brain hurt. How do people like
> Michele Simionato and David Mertz figure these things out? Does it all
> come to looking at the C source code for the CPython interpreter?
>
> Brain hurts, seriously.

I actually did rely on looking at the C source.  There's a surprising
amount of checking involving metaclass, layout, special methods, and
so on that is involved when creating a new type.


Carl Banks



More information about the Python-list mailing list