On Fri, Mar 1, 2013 at 7:37 AM, Eric Snow firstname.lastname@example.org wrote:
On Thu, Feb 28, 2013 at 11:02 AM, Nick Coghlan email@example.com wrote:
And PEP 422 is designed to make it easier to share a common __prepare__ method with different post processing.
A major use case for __prepare__() is to have the class definition use an OrderedDict. It's even a point of discussion in PEP 3115. While I agree with the the conclusion of the PEP that using only OrderedDict is inferior to __prepare__(), I also think defaulting to OrderedDict is viable and useful.
Using __prepare__() necessitates the use of a metaclass, which most people consider black magic. Even when you can inherit from a class that has a custom metaclass (like collections.abc.ABC), it still necessitates inheritance and the chance for metaclass conflicts. While I'm on board with PEP 422, I'm not clear on how it helps here.
(catching up after moving house, haven't read the whole thread)
PEP 422 would make it useful to also add a "namespace" meta argument to type.__prepare__ to give it a namespace instance to return. Then, all uses of such a OrderedDict based metaclass can be replaced by:
class MyClass(namespace=OrderedDict()): @classmethod def __init_class__(cls): # The class namespace is the one we passed in!
You could pass in a factory function instead, but I think that's a net loss for readability (you would lose the trailing "()" from the empty namespace case, but have to add "lambda:" or "functools.partial" to the prepopulated namespace case)
Even if type wasn't modified, you could create your own metaclass that accepted a namespace and returned it:
class UseNamespace(type): def __prepare__(cls, namespace): return namespace
class MyClass(metaclass=UseNamespace, namespace=OrderedDict()) @classmethod def __init_class__(cls): # The class namespace is the one we passed in!
I prefer the approach of adding the "namespace" argument to PEP 422, though, since it makes __init_class__ a far more powerful and compelling idea, and between them the two ideas should cover every metaclass use case that *only* customises creation rather than ongoing behaviour.
I actually had this idea a week or so ago, but packaging discussions and moving meant I had postponed writing it up and posting it.