[Python-3000] Metaclasses in Py3K
talin at acm.org
Sat Dec 16 20:30:19 CET 2006
Guido van Rossum wrote:
> I've been thinking about this too, and I think it's reasonable to let
> the metaclass provide the dict to be used as locals. This is easier
> when the metaclass is given in the class header, e.g. by way of a base
> class, or through the default metaclass. Although the default default
> metaclass could of course have a hook to pass things on to another
> metaclass specified using a __metaclass__ assignment, I'd rather
> innovate a bit more and add keyword arguments to the class header,
> class C(B1, B2, metaclass=Foo):
> How can we design this feature without yet another gigantic
> contentious thread? I'm losing my appetite for those. I wonder if the
> right thing wouldn't be if you could do some serious research into the
> best possible semantics, syntax and implementation, and then post a
> fully-formed proposal (not quite a PEP). There is of course always the
> danger that you might go off into the deep end with that, so I'll
> leave it up to your judgement to decide when to post again. (Also, I'm
> still quite restricted in my internet access, at least until Monday.)
Well, the discussion happened anyway, although it wasn't as bad as it
could have been.
So here's the summary of issues. First, I didn't see much resistance to
the basic idea itself. There are enough use cases, I think, to make it a
substantial win regardless of how it looks.
The main controversies are:
1) How generalized the syntax should be.
Several people, upon seeing your suggestion of "metaclass=Foo", saw an
opportunity to use that as a hook for a whole bunch of other
class-definition-related features (interface, implements, etc.). This
apparently caused a counter-reaction by people who didn't want to see
this kind of open-ended generalization (or who objected for other
reasons), and resulted in a number of proposals to deliberately limit
the syntax in ways that made this kind of expansion was impossible.
There's also Josiah Carlson's proposal which separates the 'metaclass'
function into two parts, the 'dict creation part' and the 'class
finishing part'. (I.e. type= and dict=.) I would rather see them
unified, as it makes the class declaration syntax simpler, and it's easy
enough to write a metaclass that does one or the other or both.
My personal feeling on this issue is that just because the "keyword=X"
syntax opens up other possibilities, doesn't mean we have to use them. I
think what you've proposed is intuitive and attractive, and if we don't
want to allow other kinds of keywords there, we don't have to. However,
I don't have a strong feeling on the issue either way.
I do slightly prefer "metaclass=" or "metatype=" to just "type=",
because we're talking about the type of a type, and I think it's
confusing to just say "the type is X" when we're declaring a class. I
think it's better to make the distinction between type and metatype
2) What should the interface on the metaclass look like.
The general idea is to have the metaclass create a mapping object which
is used as the 'locals' dictionary for the suite following the class
statement. There would be some special-named function of the metaclass,
such as '__metadict__', which would construct a new mapping object. I
haven't seen many alternative proposals to this.
3) How to implement it under the hood.
As was mentioned in the discussion, class bodies do not use fast locals,
so it's primarily a matter of swapping one dictionary for another. (I
may be wrong here - there may be more involved than just that.)
(I appreciate the requirement of more concrete implementation details as
a useful bozo-filter, but I'm not confident in my ability to reason
correctly about the Python C source code; At least, my past experiences
with it have have less than satisfactory results in terms of time spent
vs. benefit gained. If that makes me an ignorable bozo, then I'm cool
with that. :) )
4) Backwards compatibility
It might be possible to retain backwards compatibility if desired. In
the proposed scheme, the metaclass is invoked twice - once to create the
dictionary, and once to 'finish' the class. Note that the second step is
identical to the operation of the current __metaclass__ feature.
Thus, we can say that if the older __metaclass__ syntax is used, then
only the second, finishing step is performed; If the newer syntax is
used, then the metaclass also has an opportunity to create the mapping
More information about the Python-3000