Another way to spell __metaclass__ ?

Bengt Richter bokr at oz.net
Fri Dec 13 01:08:42 EST 2002


I must confess there is something that bothers me about __metaclass__ as
an impementation of metaclass functionality. It strikes me more as a
class transmogrification hook with a debug/trace flavor than a clear expression
of the relationship between two classes, one of which produces the other
as an instance.

I.e., to me, the hallmark of a metaclass is that it produces another class when
instantiated (normally with variations based on conditions or parameters, or why
do it).

Below is an example experiment, viewing a metaclass as a class that will create
another class as its instance, but by retrieving prototype class elements from
an existing ordinary class instead of having it transmitted by an event at the
end of the latter class definition execution (protoclass below is just a helper).

 >>> def protoclass(cls):
 ...     """return cls, name, bases, cdict copies like __metaclass__ parameters"""
 ...     return cls, cls.__name__, cls.__bases__, cls.__dict__.copy()
 ...
 >>> class MCExample(type):
 ...     def __new__(cls, proto, *args):
 ...         pccls, pcname, pcbases, pcdict = protoclass(proto)
 ...         pcdict['params'] = args # minimal parameterization
 ...         return type.__new__(cls, pcname+'_mod_'+cls.__name__, pcbases, pcdict)
 ...
 >>> class P(object):
 ...     classvar = 'P classvar'
 ...     def foo(self, x): print 'Hello from prototype foo, called with %s' % x
 ...
 >>> C = MCExample(P, 123, 'some metaclass args', 456)
 >>> C
 <class '__main__.P_mod_MCExample'>
 >>> c=C()
 >>> c
 <__main__.P_mod_MCExample object at 0x0079E520>
 >>> c.classvar
 'P classvar'
 >>> c.foo('spam')
 Hello from prototype foo, called with spam
 >>> c.params
 (123, 'some metaclass args', 456)
 >>> c.__class__
 <class '__main__.P_mod_MCExample'>
 >>> c.__class__.__class__
 <class '__main__.MCExample'>
 >>> c.__class__.__class__.__class__
 <type 'type'>

This allows the use of the prototype as an ordinary class as well:

 >>> p = P()
 >>> p.classvar
 'P classvar'
 >>> p.foo('eggs')
 Hello from prototype foo, called with eggs

But since p is a P instance, not a P_mod_MCExample instance, we don't find params:

 >>> p.params
 Traceback (most recent call last):
   File "<stdin>", line 1, in ?
 AttributeError: 'P' object has no attribute 'params'

 >>> p.__class__
 <class '__main__.P'>
 >>> p.__class__.__class__
 <type 'type'>

This is just a preliminary experiment to see how the semantics feel looking from the
other direction. IOW, you just use the metaclass like an ordinary class that happens
to produce another class, using a prototype class as a starting point, except the
metaclass expresses the link to the prototype, not the other way around. There is no
__metaclass__ attribute in the prototype class.

Regards,
Bengt Richter



More information about the Python-list mailing list