[Python-Dev] Submitting PEP 422 (Simple class initialization hook) for pronouncement

Stefan Behnel stefan_ml at behnel.de
Sun Feb 10 17:48:41 CET 2013


Antoine Pitrou, 10.02.2013 15:28:
> On Mon, 11 Feb 2013 00:09:55 +1000 Nick Coghlan wrote:
>> As far as the maintenance burden goes, the patch to enable PEP 422 for
>> types.new_class() is trivial:
>>
>> -    return meta(name, bases, ns, **kwds)
>> +    cls = meta(name, bases, ns, **kwds)
>> +    try:
>> +        initcl = cls.__init_class__
>> +    except AttributeError:
>> +        pass
>> +    else:
>> +        initcl()
>> +    return cls
> 
> I didn't know types.new_class(). I suppose that's because I'm not part
> of the top half dozen people on the planet :-) I've stopped trying to
> understand when I saw about the __build_class__ additions and whatnot.
> I now consider that part of the language totally black magic.
> 
> I'm not sure it's a good thing when even some maintainers of the
> language don't understand some of its (important) corners.

I, for one, only learned most of this stuff when we implemented it for
Cython and I'm sure there are lots of little details that I'm not aware of.
Use cases are too rare to fully learn it and the matter is certainly complex.


>> The change in the builtin.__build_class__ implementation is similarly
>> trivial (and has the same semantics), it's just more verbose due to
>> its being written in C.
> 
> Sure, every little addition is "trivial". At the end you have a scary
> monster made of many little trivial additions along the years, and
> everyone has to take care not to break it.

FWIW, I agree with Nick that this actually kills some use cases of
metaclasses and could thus lower the barrier for "doing stuff to classes"
for those who don't want to dig into metaclasses for one reason or another.

However, it's hard to say if this "new way of doing it" doesn't come with
its own can of worms. For example, would cooperative calls to
"__init_class__" work if a superclass already defines it? Do implementors
have to remember that? And is it clear how this should be done, e.g. what
should normally go first, my own code or the superclass call? Supporting
cooperative __init_class__() calls properly might actually be a good thing.
Currently, there's only one metaclass, plus a sequence of decorators, which
makes the setup rather static and sometimes tedious for subclasses that
need to do certain things by themselves, but in addition to what happens
already.

So, the way to explain it to users would be 1) don't use it, 2) if you
really need to do something to a class, use a decorator, 3) if you need to
decide dynamically what to do, define __init_class__() and 4) don't forget
to call super's __init_class__() in that case, and 5) only if you need to
do something substantially more involved and know what you're doing, use a
metaclass.

Sounds a bit smoother than the current metaclass hole that we throw people
into directly when a decorator won't catch it for them.

It's usually not a good idea to add complexity for something that's
essentially a rare use case. Only the assumption that it might actually
make it easier for users to handle certain other use cases where they'd
currently end up with their own home-grown metaclass is a point that makes
it worth considering for me. But then again, maybe these use cases are
really rare enough to just let people figure out how to do it with
metaclasses, or even a combination of metaclasses and decorators.

Stefan




More information about the Python-Dev mailing list