[Python-Dev] [Python-checkins] peps: Add PEP 422: Dynamic Class Decorators

Nick Coghlan ncoghlan at gmail.com
Wed Jun 6 01:38:39 CEST 2012


On Wed, Jun 6, 2012 at 9:06 AM, PJ Eby <pje at telecommunity.com> wrote:
>
>
> On Tue, Jun 5, 2012 at 5:31 PM, Terry Reedy <tjreedy at udel.edu> wrote:
>>
>> On 6/5/2012 2:26 PM, PJ Eby wrote:
>>> It's for symmetry and straightforward translation with stacked
>>> decorators, i.e. between:
>>>
>>> @deco1
>>> @deco2
>>> [declaration]
>>>
>>> and __decorators__ = [deco1, deco2]
>>>
>>> Doing it the other way now means a different order for people to
>>> remember; there should be One Obvious Order for decorators, and the one
>>> we have now is it.
>>
>>
>> You and I have different ideas of 'obvious' in this context.
>
>
> To be clearer: I've written other APIs which take multiple decorators, or
> things like decorators that just happen to be a pipeline of functions to be
> applied, and every time the question of what order to put the API in, I
> always put them in this order because then in order to remember what the
> order was, I just have to think of decorators.  This is easier than trying
> to remember which APIs use decorator order, and which ones use reverse
> decorator order.
>
> So, even though in itself there is no good reason for one order over the
> other, consistency wins because less thinking.  At the least, if they're not
> going to be in decorator order, the member shouldn't be called
> "__decorators__".  ;-)

Yeah, I can actually make decent arguments in favour of either order,
but it was specifically "same order as lexical decorators" that tipped
the balance in favour of the approach I wrote up in the PEP.

It's also more consistent given how the base classes are walked. While
I'm not proposing to calculate it this way, you can look at the scheme
the PEP as:

    # Walk the MRO to build a complete decorator list
    decorators = []
    for entry in cls.mro():
        decorators.extend(cls.__dict__.get("__decorators__", ())
    # Apply the decorators in "Last In, First Out" order, just like
unwinding a chain of super() calls
    for deco in reversed(decorators):
        cls = deco(cls)

Cheers,
Nick.

-- 
Nick Coghlan   |   ncoghlan at gmail.com   |   Brisbane, Australia


More information about the Python-Dev mailing list