Order in metaclass

Bengt Richter bokr at oz.net
Wed Oct 13 23:35:47 CEST 2004

On Wed, 13 Oct 2004 09:28:29 -0300, Carlos Ribeiro <carribeiro at gmail.com> wrote:

>On Wed, 13 Oct 2004 13:50:00 +0200, Peter Otten <__peter__ at web.de> wrote:
>> Bengt Richter wrote:
>> > Or, an ugly hack that might work for a while, depending on how
>> > co_names is really generated. It seems in order of occurrence
>> > (including right hand sides of assignment, but still top down) ...
>> >
>> > >>> import sys
>> > >>> def getnames(): return sys._getframe(1).f_code.co_names
>> > ...
>> > >>> def MC(cname, cbases, cdict):
>> > ...     names = cdict.get('ordic',[])
>> > ...     names = [name for name in names if name in cdict]
>> > ...     cdict['ordic'] = dict([(name,i) for i,name in enumerate(names)])
>> > ...     return type(cname, cbases, cdict)
>> > ...
>> > >>> class C(object):
>> > ...     __metaclass__ = MC # really a function shortcut
>> > ...     x = 123
>> > ...     y = sys
>> > ...     z = 0
>> > ...     ordic = getnames()
>> > ...
>> > >>> C.ordic
>> > {'ordic': 5, '__module__': 0, '__metaclass__': 1, 'y': 3, 'x': 2, 'z': 4}
>> A metaclass /function/ and sys._getframe() exercised on a class definition
>> - I think you have raised the bar for what qualifies as a hack :-)
>Hey, I came first with that a couple of weeks ago :-) but in truth, it
>was Alex Martelli that pointed to me that a metaclass function would
>work... but not only is it not recommended, it's also said to make
>Guido shudder ;-) Seriously, although it works, it's not recommended
>practice. Metaclasses are supposed to be classes, not functions.
IIRC it was Guido himself who let the cat out of the bag about a function, in
some early metaclass notes. But maybe I don't RC ;-)

>As for the getframe, I have played with it a little bit also. But in
>the end I have chosen to use a simple counter, using
>itertools.count(). More pythonic IMHO. And no need for clever hacks,
>when all that is needed is to order the elements in the order they are
>executed (which count() can guarantee). There are two situations where
>the simpler counter works, but the getframe hack doesn't:
>-- if I have a loop inside my class that is used to declare bunch of
>attributes, all of them will have the same line number... but a
>different sequence number if the simpler method is chosen.
You mean like
    for name in 'a b c'.split(): locals()[name] = ord(name[0])
? Yes, I think the names have to be visible to the compiler to show up in co_names.
>-- if a function is called that returns a bunch of attributes (not
>common practice, but still possible). All attributes are at the same
>line in this case. Example:
>class Foo:
>    a,b,c = myfunc(...)
That one _will_ show a,b,c in order. They're all visible to the compiler as names.

>Of course, we are now getting into corner cases that show how much are
>we pushing class  statements in Python. The _sane_ way to make it all
>work would be to have a hook to provide a user-defined dict to the
>class locals() dir; aternatively, the natice dict() could provide a
interestingly, you can pass a dict subtype instance as the last arg to type, but
it seems just to grab the instance's base dict. I.e., you apparently can't
get the subtype instance back as .__dict__. Oh well ;-)

>ordered interface (but then it wouldn't be a simple hash mapping, a
>more complex structure such as a tree would be needed). Both are far
>from happening in Python 2.x, IMHO... and I really doubt if dicts will
>ever be changed to accomodate ordering, even in Python 3.0. Too much
>hassle for too little gain. A hook function seems to be more sensible.
    class C(object, cdict=myDict): pass ??

Bengt Richter

More information about the Python-list mailing list