[Tutor] decorators (the "at" sign)?
Lie Ryan
lie.1296 at gmail.com
Tue Oct 26 14:30:32 CEST 2010
On 10/26/10 13:46, Alex Hall wrote:
> Hi all,
> Now that I am able to run the source code of an open source
> application I hope to one day help develop, I am trying to understand
> how it works. One thing I keep seeing is an at sign followed by a
> word, usually (maybe always) immediately preceeding a function
> definition. For example, and I know this exact code will not make much
> sense, but it gives the idea:
> class Bing(Messages, Updating, Dismissable):
>
> @set_index
> def get_url(self, index=None):
> return self.storage[index]['Url']
>
> What is the "@set_index" for? Specifically, what is the at sign doing?
> Google was only able to provide me with a very vague idea of what is
> going on, though it seems to crop up a lot in classmethod and
> staticmethod calls (not sure about those either). I read PEP 318, but
> it was not much help since I am coming at this having no idea what I
> am looking at. The PEP did explain why I have never run into this
> before, though - it is apparently specific to Python. I see this sort
> of thing all over this source code so it seems like a good idea to get
> exactly what it is for. TIA!
The decorator syntax is really just a shorthand, from this:
@decorator
def func(arg):
pass
is equivalent to:
def func(arg):
pass
func = decorator(func)
basically, a decorator is a function that takes an function as a
parameter/callable and (usually) returns another function/callable as
return value.
A slightly advanced usage of decorator:
def trace(func):
""" trace will print the func's name, the number of times
func have been called, the arguments it's called with,
and the return value of func whenever func is called.
"""
# define an inner function
def _decorator(arg):
print ("The %sth call of %s with arg: %s" %
(_decorator._numcall, func.__name__, arg))
_decorator._numcall += 1
ret = func(arg)
print "finished", func.__name__, "returns:", ret
return ret
# this is used to store the number of times
# the decorated function is called
_decorator._numcall = 0
# disable the decorator when debugging is enabled
if __debug__: # or: return _decorator if __debug__ else func
return _decorator
else:
return func
@trace
def twice(arg):
return 2 * arg
# the @trace makes it as if you do this:
# twice = trace(twice)
$ # let's start the program
$ python decor.py
The 0th call of twice() with arg: 30
finished twice() returns: 60
The 1th call of twice() with arg: 3
finished twice() returns: 6
The 2th call of twice() with arg: 4
finished twice() returns: 8
74
$
$ # now call it with debugging disabled:
$ python -O decor.py
74
another nifty use of decorator is for event handling for a hypothetical
GUI toolkit (I've yet to actually see a toolkit that uses this syntax yet):
@button.on_click
def shoot(button):
...
@window.on_keypress('p')
def pause(key):
...
other built-in functions designed for decorator syntax is @property,
@classmethod, and @instancemethod. Decorator can become extremely
powerful when combined with the descriptor protocol (.__get__, .__set__).
More information about the Tutor
mailing list