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)
initcl = cls.__init_class__
- except AttributeError:
- 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.