[Python-Dev] Providing a mechanism for PEP 3115 compliant dynamic class creation (original) (raw)

Daniel Urban urban.dani+py at gmail.com
Sun Apr 15 11:36:29 CEST 2012


On Tue, Apr 19, 2011 at 16:10, Nick Coghlan <ncoghlan at gmail.com> wrote:

In reviewing a fix for the metaclass calculation in buildclass [1], I realised that PEP 3115 poses a potential problem for the common practice of using "type(name, bases, ns)" for dynamic class creation.

Specifically, if one of the base classes has a metaclass with a significant prepare() method, then the current idiom will do the wrong thing (and most likely fail as a result), since "ns" will probably be an ordinary dictionary instead of whatever prepare() would have returned. Initially I was going to suggest making buildclass part of the language definition rather than a CPython implementation detail, but then I realised that various CPython specific elements in its signature made that a bad idea.

Are you referring to the first 'func' argument? (Which is basically the body of the "class" statement, if I'm not mistaken).

Instead, I'm thinking along the lines of an "operator.prepare(metaclass, bases)" function that does the metaclass calculation dance, invoking prepare() and returning the result if it exists, otherwise returning an ordinary dict. Under the hood we would refactor this so that operator.prepare and buildclass were using a shared implementation of the functionality at the C level - it may even be advisable to expose that implementation via the C API as PyTypePrepareNamespace().

prepare also needs the name and optional keyword arguments. So it probably should be something like "operator.prepare(name, bases, metaclass, **kw)". But this way it would need almost the same arguments as build_class(func, name, *bases, metaclass=None, **kwds).

The correct idiom for dynamic type creation in a PEP 3115 world would then be:

 from operator import prepare  cls = type(name, bases, prepare(type, bases)) Thoughts?

When creating a dynamic type, we may want to do it with a non-empty namespace. Maybe like this (with the extra arguments mentioned above):

from operator import prepare ns = prepare(name, bases, type, **kwargs) ns.update(my_ns) # add the attributes we want cls = type(name, bases, ns)

What about an "operator.build_class(name, bases, ns, **kw)" function? It would work like this:

def build_class(name, bases, ns, **kw): metaclass = kw.pop('metaclass', type) pns = prepare(name, bases, metaclass, **kw) pns.update(ns) return metaclass(name, bases, pns)

(Where 'prepare' is the same as above). This way we wouldn't even need to make 'prepare' public, and the new way to create a dynamic type would be:

from operator import build_class cls = build_class(name, bases, ns, **my_kwargs)

Daniel



More information about the Python-Dev mailing list