[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