Order in metaclass

Carlos Ribeiro carribeiro at gmail.com
Wed Oct 13 14:28:29 CEST 2004

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.

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.

-- 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(...)

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
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.

Carlos Ribeiro
Consultoria em Projetos
blog: http://rascunhosrotos.blogspot.com
blog: http://pythonnotes.blogspot.com
mail: carribeiro at gmail.com
mail: carribeiro at yahoo.com

More information about the Python-list mailing list