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

R. David Murray rdmurray at bitdance.com
Wed Jun 6 03:53:22 CEST 2012


On Wed, 06 Jun 2012 09:38:39 +1000, Nick Coghlan <ncoghlan at gmail.com> wrote:
> 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.

I don't think about data structures lexically, though, I think of them
programmatically.  So I'm with Terry here, I would expect them to be in
the list in the order they are going to get applied.  I can see the
other argument, though, and presumably other people's brains work
differently and they'd be more confused by non-lexical ordering.

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

Assuming I got this right (no guarantees :), the following is actually
easier for me to understand (I had to think to understand what "just
like unwinding a chain of super() calls" meant):

      # Walk the MRO from the root, applying the decorators.
      for entry in reversed(cls.mro()):
          for deco in cls.__dict__.get("__decorators__", ()):
             cls = deco(cls)

--David


More information about the Python-Dev mailing list