[Python-Dev] metaclass insanity

Michael Hudson mwh@python.net
30 Oct 2002 14:36:20 +0000


Kevin Jacobs <jacobs@penguin.theopalgroup.com> writes:

> On 30 Oct 2002, Michael Hudson wrote:
> > For moderately nefarious reasons[1] I've being trying to write a
> > metaclass whose instances have writable __bases__.  This in itself
> > isn't so hard, but having assigments to __bases__ "do the right thing"
> > has eluded me, basically because I can't seem to affect the mro.
> 
> The mro is an internal data structure of new-style classes, so redefining
> mro() doesn't change the values used.

Yeah, I noticed that eventually.

> Here is my (non-working version) that
> attempts to re-assign the class of an object, although it fails on a layout
> violation with Python 2.2.2.
> 
> def base_getter(cls):
>   return cls.__my_bases__
> 
> def base_setter(cls,bases):
>   if not bases:
>     bases = (object,)
>   metaclass = getattr(cls, '__metaclass__', type)
>   new_cls = metaclass(cls.__name__, bases, dict(cls.__dict__))
>   cls.__class__ = new_cls
> 
> class MetaBase(type):
>   __bases__ = property(base_getter,base_setter)
> 
>   def __new__(cls, name, bases, ns):
>     ns['__my_bases__'] = tuple(bases)
>     return super(MetaBase, cls).__new__(cls, name, bases, ns)
> 
> class Foo(object):
>   __metaclass__ = MetaBase
> class Baz(object): pass
> 
> Foo.__bases__ = Foo.__bases__ + (Baz,)

I don't think this has a hope of working does it?  This approach would
need to rebind "Foo" in the last line, no?

> Which results in:
>   TypeError: __class__ assignment: 'Foo' object layout differs from 'MetaBase'
> 
> I haven't looked into why this is being flagged as a layout error, though
> my first instinct is to say that the check is too conservative in this case.
> I'll think about it more and dig into the code.

I think the error message gives it away: in "cls.__class__ = new_cls",
cls.__class__ is MetaBase, new_cls is the new Foo.

I guess one way of doing this would be to reimplement mro resolution
and so on in Python, which would be annoying and inefficient.  Hmm.

Cheers,
M.

-- 
  [3] Modem speeds being what they are, large .avi files were
      generally downloaded to the shell server instead[4].
  [4] Where they were usually found by the technical staff, and
      burned to CD.                                   -- Carlfish, asr