On Tue, Apr 19, 2011 at 16:10, Nick Coghlan <ncogh...@gmail.com> wrote: > In reviewing a fix for the metaclass calculation in __build_class__ > [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 __build_class__ 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 __build_class__ 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 > PyType_PrepareNamespace(). __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 _______________________________________________ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com