[Python-3000] Metaclasses in Py3K

Talin 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,
> e.g.
> 
> 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 
explicit.

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 
object.

-- Talin


More information about the Python-3000 mailing list