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

Nick Coghlan ncoghlan at gmail.com
Mon Feb 11 23:29:00 CET 2013


On 12 Feb 2013 07:44, "Guido van Rossum" <guido at python.org> wrote:
>
> On Mon, Feb 11, 2013 at 12:57 PM, PJ Eby <pje at telecommunity.com> wrote:
>>
>> On Mon, Feb 11, 2013 at 12:44 PM, Guido van Rossum <guido at python.org>
wrote:
>> > Hi Nick,
>> >
>> > I think this will make a fine addition to the language. I agree that
>> > it is superior to the alternatives and fulfills a real (if rare) need.
>> >
>> > I only have a few nits/questions/suggestions.
>> >
>> > - With PJE, I think __init_class__ should automatically be a class
>> > method.
>>
>> Actually, I didn't say that as such, because I'm not sure how the heck
>> we'd implement that.  ;-)
>>
>> For example, at what point is it converted to a classmethod?  Is it
>> going to be a slot method with special C-level handling?  Handled by
>> the compiler?  What happens if somebody makes it a
>>
>> > The same way that __new__ is automatically a class method.
>>
>> Actually, isn't it automatically a staticmethod?  Oh crap.  Now that
>> I'm thinking about it, doesn't this *have* to be a static method,
>> explicitly passing in the class?  I mean, otherwise, won't calling
>> super().__init_class__() invoke it on the base class, rather than the
>> current class?
>>
>> ISTM that EIBTI argues for the __new__/staticmethod approach,
>> especially if you're returning the class (per below)
>
>
> Let's see what Nick and the implementer say.

I think these are some interesting ideas and it's going to take me a while
to digest them and update the PEP :)

A few random thoughts:

1. I like the idea of a metaprogramming "howto" that provides advice on
choosing a suitable level of metaprogramming (with the default choice being
"use existing decorators", then escalating through creating custom
decorators all the way to creating custom metaclasses). I don't think the
PEP needs to be conditional on writing that, but I will at least add PJE's
list to the PEP itself.

2. I see the new method as more analogous to__init__ than to__new__, so the
__decorate_class__ idea makes me nervous, as it's closer to a __new__
method. Composition gets a *lot* harder when your parent class can switch
out the object on you.

3. I'm trying to avoid any custom magic specific to this method, but making
it implicitly a static or class method is fairly easy if we so choose - the
standard retrieval code during class creation can just bypass the
descriptor machinery, and wrap it in staticmethod or classmethod if it
isn't already. Given that __new__ is already implicitly static, it may be
easier to follow that precedent here rather than trying to explain why an
explicit @classmethod is needed in one case but not the other.

4.__class__ is already bound as soon as we have a class object to bind it
to, so we can't move it any earlier. However, it's already early enough to
let references to it from the new method (including the implied one in
zero-arg super) work properly. The black magic that is zero-arg super also
deals with PJE's concern about propagating the actual class up the MRO (as
it is equivalent to "super(__class__, first_argument)").

5. Implicitly walking the MRO bothers me, as it becomes a special case for
people to learn. We don't do that for __init__ or __new__, so I don't think
it makes sense to do it here. We can include a recommended structure in the
docs, where the first step is calling the parent through. As PJE suggested,
a no-op method on type will make that simple and fairly safe (people using
a metaclass hierarchy not anchored on type can figure out their own
equivalent)

Cheers,
Nick.

>
>>
>> > - Would it make any sense to require that __init_class__ *returns* the
>> > new class object (to complete the similarity with class decorators)?
>>
>> It would certainly be quite useful to do so, but in that case, perhaps
>> the method should be named __decorate_class__?  And in that event the
>> standard usage would look like:
>>
>>     def __decorate_class__(cls):
>>         cls = super().__decorate_class__(cls)
>>         # do stuff
>>         return cls
>>
>> On the other hand, one could just drop the super() requirement and
>> make the usage even simpler by having the class machinery walk the MRO
>> and pass each method the result of invoking the previous one.  Then
>> the methods are short and sweet, and super() and __class__ don't come
>> into it.  (Though I guess the class machinery could keep setting
>> __class__ to whatever the last-returned class was.)
>>
>> In his first draft, Nick implemented inheritable decorators instead,
>> using a __decorators__ attribute in the class body, or something like
>> that.  While that approach had an issue or two of its own, it's
>> possible that just going with a single __decorate_class__ method would
>> work out better.
>
>
> Half-baked idea: Maybe the base class __decorate_class__ would call the
class decorators? Or does that not make sense?
>
> --
> --Guido van Rossum (python.org/~guido)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-dev/attachments/20130212/d0954576/attachment-0001.html>


More information about the Python-Dev mailing list