Re: [Python-Dev] Metatype conflict among bases?
David Abrahams <dave@boost-consulting.com> wrote:
Consider:
class A(object): class __metaclass__(type): pass
class B(A): # TypeError: metatype conflict among bases class __metaclass__(type): pass
Now that's a weird error message at least! There's only one base (A), and I'm telling Python explicitly to use the nested __metaclass__ instead of A's __metaclass__!
Should I not be surprised that Python won't let me set the metatype explicitly?
The problem here is that B.__metaclass__ *must* be the same as, or a subclass of, A.__metaclass__, or vice versa. It doesn't matter whether the metaclass is specified implicitly or explicitly, this constraint must be met. Your code doesn't meet this constraint. Here's a revised example that does: class A(object): class __metaclass__(type): pass class B(A): class __metaclass__(A.__class__): pass B.__metaclass__ will now meet the "metaclass inheritance" constraint. See the "descrintro" document for some more info about this, and the "Putting Metaclasses To Work" book for even more info about it than you would ever want to know. :) Here's a short statement of the constraint, though: A class X's metaclass (X.__class__) must be identical to, or a subclass of, the metaclass of *every* class in X.__bases__. That is: for b in X.__bases__: assert X.__class__ is b.__class__ or issubclass(X.__class, b.__class__),\ "metatype conflict among bases"
"Phillip J. Eby" <pje@telecommunity.com> writes:
The problem here is that B.__metaclass__ *must* be the same as, or a subclass of, A.__metaclass__, or vice versa. It doesn't matter whether the metaclass is specified implicitly or explicitly, this constraint must be met. Your code doesn't meet this constraint. Here's a revised example that does:
class A(object): class __metaclass__(type): pass
class B(A): class __metaclass__(A.__class__): pass
B.__metaclass__ will now meet the "metaclass inheritance" constraint. See the "descrintro" document for some more info about this, and the "Putting Metaclasses To Work" book for even more info about it than you would ever want to know. :)
I knew all that once, and have since forgotten more than I knew :(. I actually already managed to make the code work by doing what you did above, so it couldn't have been buried too deeply in the caves of my brain.
Here's a short statement of the constraint, though:
A class X's metaclass (X.__class__) must be identical to, or a subclass of, the metaclass of *every* class in X.__bases__. That is:
for b in X.__bases__: assert X.__class__ is b.__class__ or issubclass(X.__class, b.__class__),\ "metatype conflict among bases"
Still, the message is misleading. There's only one base class, so the metatype conflict is not "among bases". -- Dave Abrahams Boost Consulting www.boost-consulting.com
David Abrahams <dave@boost-consulting.com> writes:
Still, the message is misleading. There's only one base class, so the metatype conflict is not "among bases".
Not arguing with that, but: what would you suggest instead? I'm agin the idea of having small essays in tracebacks... Cheers, M. -- People think I'm a nice guy, and the fact is that I'm a scheming, conniving bastard who doesn't care for any hurt feelings or lost hours of work if it just results in what I consider to be a better system. -- Linus Torvalds
Michael Hudson <mwh@python.net> writes:
David Abrahams <dave@boost-consulting.com> writes:
Still, the message is misleading. There's only one base class, so the metatype conflict is not "among bases".
Not arguing with that, but: what would you suggest instead? I'm agin the idea of having small essays in tracebacks...
metatype conflict: metatype of derived class B must be a (non-strict) subclass of the metatypes of its bases I don't think that's too verbose. Too many traceback messages from Python give no indication of what the actual problem was or how to fix it, so I don't mind getting a bit more essay-like. Just today on python-list I saw this >>> range(map(lambda x:x+1, [0, 100, 3])) Traceback (most recent call last): File "<stdin>", line 1, in ? TypeError: an integer is required come up as a problem for someone. -- Dave Abrahams Boost Consulting www.boost-consulting.com
On Wednesday 23 April 2003 02:17 pm, David Abrahams wrote: ...
it, so I don't mind getting a bit more essay-like. Just today on python-list I saw this
>>> range(map(lambda x:x+1, [0, 100, 3]))
Traceback (most recent call last): File "<stdin>", line 1, in ? TypeError: an integer is required
come up as a problem for someone.
It's a bit better in the current CVS Python -- essentially all error messages from built-ins now identify which built-in is involved, and many give extra, pertinent information -- e.g.: [alex@lancelot src]$ ./python -c 'range(map(str,[1,2,3]))' Traceback (most recent call last): File "<string>", line 1, in ? TypeError: range() integer end argument expected, got list. As long as the message still typically fits within one line, I think there can be no substantial objection to making it clearer and more infomative. Alex
participants (4)
-
Alex Martelli
-
David Abrahams
-
Michael Hudson
-
Phillip J. Eby