Strange metaclass behaviour

Christian Eder chris.eder at gmx.at
Thu Mar 23 13:30:22 EST 2006


Michele Simionato wrote:

> Still, it is an interesting exercise if you are willing to risk the
> melting of your brain,
> so here is the code ;)

I tried your code and it fixes the double execution, but the __new__ is 
executed in context of M_A instead of M_B which would be the more 
specific type here.

Anyway, I think I found an acceptable solution for the problem.
The question is "What Do I need to fix metaclasses ?"
And the answer, of course, is "a meta-meta-class !"

The following code solves the problem.
It's basically Ziga's code except that I added one level of abstraction
(to avoid adding this kludge code to each custom metaclasses'es __new__):

class _fixed_type_ (type) :

     def __call__ (meta, name, bases, dict) :
         meta = meta._get_meta (bases, dict)
         cls  = meta.__new__   (meta, name, bases, dict)
         meta.__init__         (cls, name, bases, dict)
         return cls
     # end def __call__

     def _get_meta (meta, bases, dict) :
         if "__metaclass__" in dict :
             return dict ["__metaclass__"]
         winner = meta
         for b in bases :
             cand = type (b)
             if cand in (types.ClassType, type) :
                  pass
             elif issubclass (cand, winner) :
                 winner = cand
             elif issubclass (winner, cand) :
                 pass
             else :
                 raise TypeError ("Metatype conflict among bases")
         return winner
     # end def _get_meta

# end class _fixed_type_

class my_type (type) :

     __metaclass__ = _fixed_type_ ### to fix metaclasses, we need
                                  ### meta-meta classes

# end class my_type


Then I made "my_type" the root of my metaclass hierarchy
(instead of "type") which solves all my problems.

After 5 years of Python, I still find it impressive how much
vodoo and mojo one can do here :-)

regards
chris



More information about the Python-list mailing list