[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