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