[Python-3000] Compiling the PEP 3115 metaclass syntax
Tony Lownds
tony at PageDNA.com
Thu Mar 15 05:33:42 CET 2007
On Mar 14, 2007, at 6:26 PM, Guido van Rossum wrote:
> The PEP proposes that the class statement accepts keyword arguments,
> *args, and **kwds syntax as well as positional bases. This is a bit
> messy to compile and execute, but we already have this, of course, in
> the code for calling regular functions.
>
> So I think it would be acceptable to this into a call to a new
> (hidden) built-in function, named __build_class__. Then that this
> class definition:
>
> class C(A, B, metaclass=M, other=42, *more_bases, *more_kwds):
> ...
>
> would translate into this:
>
> C = __build_class__(<func>, 'C', A, B, metaclass=M, other=42,
> *more_bases, *more_kwds)
>
> where <func> is a function object for the class body. (It's a slightly
> different function than currently; the current function *returns* the
> locals, while the new one *takes* the locals as an argument; instead
> of a LOAD_LOCALS opcode we need a STORE_LOCALS opcode.)
>
> Then __build_class__ could be roughly like this (but implemented in
> C):
>
> def __build_class__(func, name, *bases, metaclass=None, **kwds):
> if metaclass is None:
> metaclass = extract_metaclass(bases) # may raise an exception
> prepare = getattr(metaclass, "__prepare__", None)
> if prepare:
> locals = prepare(name, bases, **kwds)
> else:
> locals = {}
> func(locals)
> return metaclass(name, bases, locals, **kwds)
>
> What do folks think?
>
This seems elegant to me.
Does **kwds need to be passed to prepare and also to metaclass
constructor?
Removing that would make it easier to provide nice error messages.
Custom __prepare__
implementations can always store the **kwds that are needed in or on the
dictionary-like object.
Instead of a function, maybe __build_class__ can just take a code
object. Then
STORE_LOCALS won't be needed.
def __build_class__(code, name, *bases, metaclass=None, **kwds):
if metaclass is None:
metaclass = extract_metaclass(bases) # may raise an exception
prepare = getattr(metaclass, "__prepare__", None)
if prepare:
locals = prepare(name, bases, **kwds)
else:
if kwds:
raise TypeError, "default metaclass takes no extra
arguments"
locals = {}
exec(code, locals)
return metaclass(name, bases, locals)
How do you load a hidden built-in? An new opcode, like LOAD_BUILTIN?
Or is it hidden by
convention only?
LOAD_BUILTIN 0 (__build_class__)
LOAD_CONST 1 (<code object>)
LOAD_CONST 0 ('classname')
LOAD_NAME 1 (base)
CALL_FUNCTION 3
STORE_NAME 2 (name)
Thanks
-Tony
More information about the Python-3000
mailing list