[Python-3000] PEP for Metaclasses in Python 3000 (original) (raw)
Guido van Rossum guido at python.org
Tue Mar 13 18:38:29 CET 2007
- Previous message: [Python-3000] PEP for Metaclasses in Python 3000
- Next message: [Python-3000] PEP for Metaclasses in Python 3000
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
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 plainkwargs
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 classlocals()? 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/)
- Previous message: [Python-3000] PEP for Metaclasses in Python 3000
- Next message: [Python-3000] PEP for Metaclasses in Python 3000
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]