[Tutor] Metaclass confusion...

Peter Otten __peter__ at web.de
Tue Apr 19 17:25:32 CEST 2011


Modulok wrote:

> List,
> 
> I've been messing with metaclasses. I thought I understood them until I
> ran into this. (See code below.) I was expecting the generated class,
> 'Foo' to have an 'x' class-level attribute, as forced upon it by the
> metaclass 'DracoMeta' at creation. Unfortunately, it doesn't and I don't
> know why. I'm obviously missing something big. I thought a metaclass
> created the class object, so this should work. (But obviously doesn't.)
> 
> 
> <!-- Begin Code -->
> class DracoMeta(type):
>     '''Metaclass that creates a serial number as a class property.'''
>     def __init__(self, name, bases, members):
>         # Force a class attribute on the class-to-be:
>         members['serial'] = 3
> 
>         # Now make the class:
>         type.__init__(self, name, bases, members)
> 
> class Foo(object):
>     __metaclass__ = DracoMeta
> 
> print hasattr(Foo, 'serial')    #<-- I was really expecting this to be
> True. <!-- End Code -->
> 
> I could add the attribute in the definition or a decorator, but the point
> was learning to use (albeit abuse) metaclasses. Anyway, if anyone could
> take a look I'd be grateful.

You are a little late to the show; the class, i. e. the instance of the 
metaclass with all its attributes has already been created by the 
type.__new__() method. If you move the manipulation of the members dict into 
a custom __new__() method you get the desired behaviour:

>>> class DracoMeta(type):
...     def __new__(cls, name, bases, members):
...             members["serial"] = 3
...             return type.__new__(cls, name, bases, members)
...
>>> class Foo:
...     __metaclass__ = DracoMeta
...
>>> Foo.serial
3

Alternatively you can take advantage of the fact that 'self' in the 
metaclass is the metaclass instance, i. e. the class, and assign directly to 
it:

>>> class NianMeta(type):
...     def __init__(self, name, bases, members):
...             self.serial = 3
...
>>> class Bar:
...     __metaclass__ = NianMeta
...
>>> Bar.serial
3




More information about the Tutor mailing list