(Sorry I'm so late to this discussion.)
I think that it's important to take into account the fact that PEP 3115 doesn't require namespaces to implement anything more than __setitem__ and __getitem__ (with the latter not even needing to do anything but raise KeyError).
Among other things, this means that .update() is right out as a general-purpose solution to initializing a 3115-compatible class: you have to loop and set items explicitly. So, if we're providing helper functions, there should be a helper that handles this common case by taking the keywords (or perhaps an ordered sequence of pairs) and doing the looping for you.
Of course, once you're doing that, you might as well implement it by passing a closure into __build_class__...
On Sun, Apr 15, 2012 at 7:48 AM, Nick Coghlan email@example.com wrote:
Yup, I believe that was my main objection to exposing __build_class__ directly. There's no obligation for implementations to build a throwaway function to evaluate a class body.
Thing is, though, if an implementation is dynamic enough to be capable of supporting PEP 3115 *at all* (not to mention standard exec/eval semantics), it's going to have no problem mimicking __build_class__.
I mean, to implement PEP 3115 namespaces, you *have* to support exec/eval with arbitrary namespaces. From that, it's only the tiniest of steps to wrapping that exec/eval in a function object to pass to __build_class__.
Really, making that function is probably the *least* of the troubles an alternate implementation is going to have with supporting PEP 3115 (by far). Hell, supporting *metaclasses* is the first big hurdle an alternate implementation has to get over, followed by the exec/eval with arbitrary namespaces.
Personally, I think __build_class__ should be explicitly exposed and supported, if for no other reason than that it allows one to re-implement old-style __metaclass__ support in 2.x modules that rely on it... and I have a lot of those to port. (Which is why I also think the convenience API for PEP 3115-compatible class creation should actually call __build_class__ itself. That way, if it's been replaced, then the replaced semantics would *also* apply to dynamically-created classes.)
IOW, there'd be two functions: one that's basically "call __build_class__", and the other that's "call __build_class__ with a convenience function to inject these values into the prepared dictionary".
Having other convenience functions that reimplement lower-level features than __build_class__ (like the prepare thing) sounds like a good idea, but I think we should encourage common cases to just call something that keeps the __setitem__ issue out of the way.