Possible bug in "metaclass resolution order" ?
Bengt Richter
bokr at oz.net
Mon Sep 19 01:22:09 EDT 2005
On Sat, 17 Sep 2005 12:41:09 -0300, Pedro Werneck <pedro.werneck at terra.com.br> wrote:
>On 17 Sep 2005 02:04:39 -0700
>"Simon Percivall" <percivall at gmail.com> wrote:
>
>> Have you read the "Metaclasses" part of "Unifying types and classes in
>> Python 2.2"? (http://www.python.org/2.2.3/descrintro.html#metaclasses)
>
>Yes, I read. Have you read and understood my message ? :)
>
>A class B, subclass of class A, with a metaclass M_A should have M_A or
>a subclass of it as metaclass. If you try with anything else, you get a
>TypeError exception as expected. OK. But if you try with 'type', nothing
>happens.
>
>Python 2.4.1 (#1, Sep 16 2005, 17:47:47)
>[GCC 3.3.4] on linux2
>Type "help", "copyright", "credits" or "license" for more information.
>>>> class M_A(type): pass
>...
>>>> class A: __metaclass__ = M_A
>...
>>>> class B(A): __metaclass__ = type
>...
>>>> B.__class__
><class '__main__.M_A'>
>>>> B.__metaclass__
><type 'type'>
>
FWIW, I think __metaclass__ can be any callable, but it seems to be the
first argument to type.__new__ that invokes the checking and
type(name, bases, cdict) seems to have the same effect as
type.__new__(type, name, bases, cdict). Maybe there has to be
a "real" class on the mro, and type isn't one, or it's a wild card ;-)
I haven't really grokked the error message's true meaning, not having
dealt with metaclass conflict before. Not ready today, sorry ;-)
>>> class M_A(type): pass
...
>>> class A: __metaclass__ = M_A
...
>>> def foo(*args): print args; return 'silliness'
...
>>> def foo(cname, cbases, cdict):
... print 'cname, cbases:', cname, cbases
... print 'cdict:', cdict
... mt = type('M_B',(type,),{})
... print 'mt:', mt
... print 'mt.mro(mt):', mt.mro(mt)
... print 'mt.__new__:', mt.__new__
... something = mt.__new__(mt, cname, cbases, cdict)
... print 'something:', something
... return something
...
>>> class B(A): __metaclass__ = foo
...
cname, cbases: B (<class '__main__.A'>,)
cdict: {'__module__': '__main__', '__metaclass__': <function foo at 0x02EEBD84>}
mt: <class '__main__.M_B'>
mt.mro(mt): [<class '__main__.M_B'>, <type 'type'>, <type 'object'>]
mt.__new__: <built-in method __new__ of type object at 0x1E1BF670>
Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 8, in foo
TypeError: Error when calling the metaclass bases
metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the
metaclasses of all its bases
>>> def bar(cname, cbases, cdict):
... print 'cname, cbases:', cname, cbases
... print 'cdict:', cdict
... mt = type
... print 'mt:', mt
... print 'mt.mro(mt):', mt.mro(mt)
... print 'mt.__new__:', mt.__new__
... something = mt.__new__(mt, cname, cbases, cdict)
... print 'something:', something
... return something
...
>>> class B(A): __metaclass__ = bar
...
cname, cbases: B (<class '__main__.A'>,)
cdict: {'__module__': '__main__', '__metaclass__': <function bar at 0x02EEBDF4>}
mt: <type 'type'>
mt.mro(mt): [<type 'type'>, <type 'object'>]
mt.__new__: <built-in method __new__ of type object at 0x1E1BF670>
something: <class '__main__.B'>
>>>
And the something returned, whatever it is, if no checking is triggered by normal use,
gets bound to the class name, e.g.,
>>> class C(A): __metaclass__ = lambda *a:('silly', 'result')
...
>>> C
('silly', 'result')
Regards,
Bengt Richter
More information about the Python-list
mailing list