+1 on the PEP. FWIW, it may be useful to note that not only has the pattern of having a class-level init been proposed before, it's actually used: Zope has had __class_init__ and used it as a metaclass alternative since well before Thomas Heller's proposal.<br>
<br>And in my case, about 80% of my non-dynamic metaclass needs are handled by using a metaclass whose sole purpose is to provide me with __class_init__, __class_new__, and __class_call__ methods so they can be defined as class methods instead of as metaclass methods. (Basically, it lets me avoid making new metaclasses when I can just define __class_*__ methods instead. The other use cases are all esoterica like object-relational mapping, singletons and pseudo-singletons. etc.)<br>
<br>So, the concept is a decades-plus proven alternative to metaclasses for low-hanging metaclassy behavior.<br><br>This new version of the PEP does offer one challenge to my motivating use case, though, and that's that hooking __init_class__ means any in-body decorators have to occur *after* any __init_class__ definition, or silent failure will occur. (Because a later definition of __init_class__ will overwrite the dynamically added version.)<br>
<br>While this challenge existed for the __metaclass__ hook, it was by convention always placed at the top of the class, or very near to it. After all, knowing what metaclass a class is, is pretty important, *and* not done very often. Likewise, had the previous version of the PEP been used, it was unlikely
that anybody would bury their __decorators__ list near the end of the class! The __init_class__ method, on the other hand, can quite rightly be considered a minor implementation detail internal to a class that might reasonably be placed late in the class definition. <br>
<br>This is a relatively small apprehension, but it makes me *slightly* prefer the previous version to this one, at least for my motivating use case. But I'll admit that this version might be better for Python-as-a-whole than the previous version. Among other things, it makes my "classy" metaclass (the one that adds __class_init__, __class_call__, etc.) redundant for its most common usage (__class_init__).<br>
<br>I'm tempted to suggest adding a __call_class__ to the mix, since in grepping my code to check my less-esoteric metaclass use cases just now, I find I implement __class_call__ methods almost as often as __class_init__ ones, but I suspect my use cases are atypical in this regard. (It's mostly used for things where you want to hook instance creation (caches, singletons, persistence, O-R mapping) while still allowing subclasses to define __new__ and/or __init__ without needing to integrate with the tricky bits.)<br>
<br>(To be clear, by esoteric, I mean cases where I'm making classes that act like non-class objects in some regard, like a class that acts as a mapping or sequence of its instances. If all you're doing is making a class with a sprinkling of metaprogramming for improved DRYness, then __class_init__ and __class_call__ are more than enough to do it, and a full metaclass is overkill.)<br>
<br>