Choosing a Metaclass?

Steve Holden steve at holdenweb.com
Thu Feb 21 15:01:36 EST 2008


Jeff McNeil wrote:
> Hi list,
> 
> Hopefully a quick metaclass question. In the following example, MyMeta 
> is a metaclass that does not inherit directly from type:
> 
> #!/usr/bin/python
> 
> class MyMeta(object):
>     def __new__(cls, name, bases, vars):
>         print "MyMeta.__new__ called for %s" % name
>         return type(name, bases, vars)
> 
> class MetaWrapper(object):
>     __metaclass__ = MyMeta
> 
> class M(MetaWrapper):
>     pass
> 
> [jeff at marvin ~]$ python t.py
> MyMeta.__new__ called for MetaWrapper
> [jeff at marvin ~]$
> 
> When I run that script, it's apparent that although M inherits from 
> MetaWrapper, it does not use MyMeta as it's metaclass.  However, if I 
> change MyMeta to be a subclass of builtin type, it works as I would expect:
> 
> [jeff at marvin ~]$ cat t.py
> #!/usr/bin/python
> 
> class MyMeta(type):
>     def __new__(cls, name, bases, vars):
>         print "MyMeta.__new__ called for %s" % name
>         return super(MyMeta, cls).__new__(cls, name, bases, vars)
> 
> class MetaWrapper(object):
>     __metaclass__ = MyMeta
> 
> class M(MetaWrapper):
>     pass
> 
> [jeff at marvin ~]$ python t.py
> MyMeta.__new__ called for MetaWrapper
> MyMeta.__new__ called for M
> [jeff at marvin ~]$
> 
> How exactly does Python choose which MC it will use when building a 
> class?  It doesn't seem to me that the parent class of MyMeta should 
> matter in this case?
> 
When you create a subclass M of MetaWrapper in your first example, 
MetaWrapper is a subclass of object that has no metaclass of its own, 
and therefore it resolves __new__() from object:

 >>> MetaWrapper.__bases__
(<type 'object'>,)
 >>> MetaWrapper.__metaclass__
<class '__main__.MyMeta'>
 >>> dir(MyMeta)
['__class__', '__delattr__', '__dict__', '__doc__', '__getattribute__', 
'__hash__', '__init__', '__module__', '__new__', '__reduce__', 
'__reduce_ex__', '__repr__', '__setattr__', '__str__', '__weakref__']
 >>> MetaWrapper.__new__
<built-in method __new__ of type object at 0x6cb92f50>

In your second example MyMeta is a subclass of type, and therefore it 
resolves type's __new__(), which is what takes the special actions you 
observe when a subclass is defined:

 >>> MetaWrapper.__bases__
(<type 'object'>,)
 >>> MetaWrapper.__metaclass__
<class '__main__.MyMeta'>
 >>> dir(MyMeta)
['__base__', '__bases__', '__basicsize__', '__call__', '__class__', 
'__cmp__', '__delattr__', '__dict__', '__dictoffset__', '__doc__', 
'__flags__', '__getattribute__', '__hash__', '__init__', '__itemsize__', 
'__module__', '__mro__', '__name__', '__new__', '__reduce__', 
'__reduce_ex__', '__repr__', '__setattr__', '__str__', '__subclasses__', 
'__weakrefoffset__', 'mro']
 >>> MetaWrapper.__new__
<built-in method __new__ of type object at 0x6cb92f50>
 >>>

Hope this helps. Remember that when there is no __metaclass__ defined in 
a class's body (and the module namespace has no default __metaclass__) 
the class's metaclass is the type of the class's first base class.

regards
  Steve
-- 
Steve Holden        +1 571 484 6266   +1 800 494 3119
Holden Web LLC              http://www.holdenweb.com/




More information about the Python-list mailing list