Self-referencing decorator function parameters

Thomas Dimson tdimson at gmail.com
Wed Apr 2 11:13:16 EDT 2008


On Apr 2, 10:31 am, George Sakkis <george.sak... at gmail.com> wrote:
> On Apr 2, 8:30 am, Thomas Dimson <tdim... at gmail.com> wrote:
>
>
>
>
>
> > Hello,
>
> > Originally I posted this as a bug but it was shot down pretty quickly.
> > I am still mildly curious about this as I'm missing a bit of
> > understanding of Python here. Why is it that the following code
> > snippet:
>
> > def decorator( call ):
> >     def inner(func):
> >         def application( *args, **kwargs ):
> >             call(*args,**kwargs)
> >             func(*args,**kwargs)
> >         return application
>
> >     return inner
>
> > class DecorateMe:
> >     @decorator( call=DecorateMe.callMe )
> >     def youBet( self ):
> >         pass
>
> >     def callMe( self ):
> >         print "Hello!"
>
> > DecorateMe().youBet()
>
> > Will not compile, giving:
> > Traceback (most recent call last):
> >   File "badpython.py", line 10, in <module>
> >     class DecorateMe:
> >   File "badpython.py", line 11, in DecorateMe
> >     @decorator( call=DecorateMe.callMe )
> > NameError: name 'DecorateMe' is not defined
>
> > Where if you change the "call=DecorateMe.callMe" to "call=lambda x:
> > DecorateMe.callMe(x)" everything goes along its merry way. Nesting the
> > call in a lambda seems to allow it to recognize the class definition.
> > Any ideas as to what is going on here (other than ugly code)?
>
> The error message is pretty obvious; when the
> "@decorator(call=DecorateMe.callMe)" line is reached, the DecorateMe
> class has not been created yet, let alone the DecorateMe.callMe
> method. One way to make it work (for some definition of "work" ;-) is
> the following:
>
> # use "new-style" classes unless you have a good reason not to:
> # class DecorateMe(object):
> class DecorateMe:
>
>     def callMe(self):
>         print "Hello!"
>
>     @decorator(call=callMe)
>     def youBet(self):
>         pass
>
> The reason this works is that at the point where @decorator is
> executed, callMe is already in the temporary namespace to be used for
> creating the DecorateMe class (although the class itself is not built
> yet).
>
> A subtle point is that in this case callMe is a plain function, not an
> (unbound) method such as DecorateMe.callMe. This may or may not
> matter, depending on what you do with it in the decorator. Some
> decorators that work fine with plain functions break if they are used
> to decorate methods (or vice versa) so it's good to have this in mind
> when writing or debugging a decorator.
>
> George- Hide quoted text -
>
> - Show quoted text -

Thanks George, that was helpful.

I guess my real question is: why does wrapping the call to be
"call=lambda x: DecorateMe.callMe(x)" somehow fix the issue with this
temporary namespace? It seems strange to me that defining an
additional function (through lambda) would allow me to see/add more
members to the namespace.



More information about the Python-list mailing list