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