[Python-Dev] [Python-checkins] peps: PEP 422 rewrite to present an idea that a) isn't crazy and b) it turns out

PJ Eby pje at telecommunity.com
Wed Jun 6 23:32:41 CEST 2012


+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.

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.)

So, the concept is a decades-plus proven alternative to metaclasses for
low-hanging metaclassy behavior.

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.)

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.

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__).

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.)

(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.)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-dev/attachments/20120606/b29273e8/attachment.html>


More information about the Python-Dev mailing list