On May 30, 6:15 pm, Carl Banks <pavlovevide...@gmail.com> wrote: > On May 30, 5:32 pm, LittleGrasshopper <seattleha...@yahoo.com> wrote: > > > > > On May 30, 4:01 pm, LittleGrasshopper <seattleha...@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
Thanks a lot, Carl. It's funny that you would post that example, as just 15 minutes ago I wrote almost the exact same code in my testing: class XMeta(type): pass class YMeta(type): pass class X(object): __metaclass__ = XMeta class Y(object): __metaclass__ = YMeta """ This causes an error, since there is no leafmost metaclass in the set {XMeta, YMeta}: class Z(X, Y): pass """ """ The way to solve this is to create a common derived metaclass and use that one for class z: """ class ZMeta(XMeta, YMeta): pass class Z(X, Y): __metaclass__ = ZMeta Looking at the C code sounds like a daunting task, but I might take a plunge and give it a try, since it seems that guessing via experimental results is not the most optimal way to go about it. Thank you again. -- http://mail.python.org/mailman/listinfo/python-list