At 08:02 PM 3/27/2006 -0800, Guido van Rossum wrote:
Just curious (and lazy): what magic is the implementation using that makes this work without a custom metaclass?
It registers a function as the __metaclass__ by poking it into the f_locals of the frame that's defining the class. This function has two attributes that denote 1) the callback to be invoked, and 2) the previous metaclass, forming a linked list of callbacks.
When the class is created, this dummy metaclass function invokes the previous metaclass (or metaclass function) in the chain, then calls its callback on the result and returns that value, thus recursively unwinding the chain of advisors in the right order. (i.e., the same order as the advisors were called in the class body).
The only part of the code that's even mildly complex is simulating Python's builtin rules for determining the default metaclass, so that when the recursion bottoms out you end up with an actual class with the right metaclass. And that's not so much complex as tedious.
Anyway, the mechanism is orthogonal to the chosen metaclass, and thus can be used with classic classes or even ExtensionClasses if you're sufficiently masochistic. :) And AFAIK it's been in use by Zope 3 for some years now; in fact I think you were still working at Zope Corp. when Steve Alexander came up with the basic idea and I made the first practical implementation.
Phillip J. Eby wrote:
It registers a function as the __metaclass__ by poking it into the f_locals of the frame that's defining the class.
That is stunningly brilliant! I'd nominate it for Hack of the Year if there were such an award.
It's far too magical for me to feel like actually using it, though. Class decorators would be so much more straightforward and explicit.