[Python-3000] PEP for Metaclasses in Python 3000

Guido van Rossum guido at python.org
Tue Mar 13 18:38:29 CET 2007


Another bulk reply...

On 3/12/07, Steven Bethard <steven.bethard at gmail.com> wrote:
> Maybe I'm misunderstanding but isn't this a reason that you'd *want*
> the ``**kwargs`` signature?  With the plain ``kwargs`` signature from
> the PEP you'd have to do something like::
>
>     def __prepare__(name, args, kwargs):
>         required = kwargs.pop('required', None)
>         if required is not None:
>             ...

There seems some confusion here. Let me try to clarify this by
specifying exactly what I meant and I betcha you'll all agree that
that's what you meant too. :-)

The __prepare__ function will be called with two positional arguments,
corresponding to the name and the tuple of base classes, respectively;
and with as many keyword arguments as were present in the class
header. Use of *args in the class header adds to the bases; use of
**kwargs adds to the keyword args. PS I'm not 100% sure of the name
__prepare__ (though I will stick for it until we find a better one),
but I *am* pretty sure that this is the most useful signature.

On 3/13/07, Nick Coghlan <ncoghlan at gmail.com> wrote:
> Along similar lines, I'd be marginally happier with:
>
>    class Bob(meta=Planet): pass
>
> over what is currently proposed in the PEP. Repeating the 'class' part
> within a single line feels redundant.

Disagree. 'meta' is an extremely generic term, and needs
qualification. Also, we've been calling these things metaclasses since
before they were properly supported. Let's stick with metaclass.

[Guido]
> > I'd like the syntax between () to be identical to that for a function
> > call, i.e. including *args and **kwds. That way the cognitive load for
> > the user is the smallest. Sorting out the semantics of the keywords is
> > purely a runtime activity anywaty.

[Nick]
> I like this idea.
>
> I think the signature of the method that creates the namespace
> dictionary requires some further thought though:
>
>   - is it intended to typically be a static method or a class method of
> the metaclass? (as it will be called before __new__, an instance method
> of the metaclass wouldn't make sense)

We have to be very careful, because the 'metaclass' doesn't even need
to be a class. I propose to use exactly these syntax:

prepare = getattr(metaclass, '__prepare__', None)
if prepare is not None:
  prepare(name, bases, **kwargs)

>   - is the metaclass passed in to the namespace creation function as a
> normal keyword argument, or is it automatically removed by the
> interpreter? (note that implementing it as a class method would still
> allow access to the actual metaclass)

For uniformity and generality I propose to keep it. So the absolute
minimal signature for __prepare__ is actually:

def __prepare__(name, bases, *, metaclass=None): ...

>   - if the metaclass is derived rather than passed in explicitly, is the
> 'meta' argument still passed in to the namespace creation function?

I think it should not be; this way the prepare function can
distinguish between an explicit and an implied metaclass. Hence the
default None above.

>   - what's the actual signature of the new function?

See above.

> The answers to these will be somewhat intertwined - if the 'meta'
> keyword argument is always going to be passed in to the function, then
> it makes more sense to use a static method in the typical case. If the
> meta keyword is stripped (or only provided when passed in explicitly),
> then a class method is needed in order to reliably get at the metaclass
> itself.

I think we shouldn't care about whether it's a class method or a
static method. It should be *callable* like above, and there are many
ways to accept this call signature. Again, remember that the
'metaclass' could be a refugar function and __prepare__ another
function stored on the former as a function attribute.

On 3/13/07, Greg Ewing <greg.ewing at canterbury.ac.nz> wrote:
> Can someone clarify something here: Are the keywords going
> to be passed to the prepare function only, or to both the
> the prepare function and the metaclass?

I think they should go to both -- otherwise you might end up having to
create a dummy __prepare__ just to pass the keyword args to the
metaclass itself.

> If they're only passed to the prepare function, it means
> that any metaclass that's interested in them will have to
> implement a prepare function that creates some object to
> hold onto them, even if it has no other need for a custom
> namespace.
>
> If they're passed to both, then the signatures become
>
>    metaclass.__prepare__(name, bases, **kwargs)
>    metaclass(name, bases, body, **kwargs)

Right.

> BTW, I don't think I like the name "__prepare__" much
> more than "__metacreate__". It seems just as wooly.
> What's being prepared? How? What for?

We're preparing a dict for use by the class body. But I'm open for
suggestions of alternate names (though this is quickly reaching the
bikeshed color level of interest). We could use __begin__, or
something else including the word "begin", as the call signals the
beginning of the class construction.

On 3/13/07, Greg Ewing <greg.ewing at canterbury.ac.nz> wrote:
[Greg]
> > >   class Foo:
> > >     class __metaclass__:

[Guido]
> > Personally, I find code that does this completely unreadable

[Greg]
> The reason I'd be a little disappointed to lose this is that
> it provides a concise way of defining genuine class methods
> (as opposed to the odd beasts created by classmethod()).
> Sometimes you need them, e.g. for __xxx__ methods, or if you
> want inheritance to work properly.

All I obect to is the nesting of the metaclass *inside* the class. It
makes the metaclass essentially non-reusable (except by inheriting
from the class in which it appears) and it ends up having a generic
name which may make it hard to debug code in which that name appears.
Also there are general issues with nested classes (e.g. they're hard
to pickle right).

> Having said that, I can't remember whether I've ever actually
> used this, and I probably wouldn't miss it all that much.

Spoken like a man. :-)

> > I find this rather cool looking:
> >
> >   class C(implements=(I1, I2)): ...

Me too. :-)

> I'm a bit worried that class headers are going to become
> rather cluttered if we start putting all sorts of stuff
> in there.
>
> E.g. are you intending to put __slots__ there? It makes
> sense, but it could lead to some rather long and
> unwieldy class headers.

It makes sense to put slots there, doesn't it? I'm not too worried
about the long class headers; a formatting convention can do wonders
here.

On 3/13/07, Greg Ewing <greg.ewing at canterbury.ac.nz> wrote:
> Is there some way we could remove the word "meta"
> from the syntax altogether? I don't mind using
> it in conversation, but it seems a tad too geeky
> to have as an actual part of the language.

Being geeky is what it's all about. :-)

> How about
>
>    class Bob(Base1, Base2, class Planet):
>      ...
>
> i.e. we're saying what we want the class of the
> class to be.

Too confusing for the reader, and breaks the IMO rather nice property
that this is now syntactically a call, with exactly all the bells and
whistles that entails, and no others.

> A benefit would be that the metaclass doesn't
> end up as being one of the keyword args in the
> first place, so there's no issue of whether to
> strip it out or not.

I don't see that as a problem (see above).

On 3/13/07, Phillip J. Eby <pje at telecommunity.com> wrote:
> How about __class_locals__()?  This would at least say exactly what the
> return value is used for.

But it doesn't convey the idea that this *creates* such a dict; it
could be misconstrued as being an accessor method for the class locals
(even though that makes no sense). I'm still in favor of __prepare__
or __begin__.

-- 
--Guido van Rossum (home page: http://www.python.org/~guido/)


More information about the Python-3000 mailing list