function decorators

N

Nick Donohue

I came across this code just now:

def time_me(function):
def wrap(*arg):
start = time.time()
r = function(*arg)
end = time.time()
print "%s (%0.3f ms)" %(function.func_name, (end-start)*1000)
return wrap

@time_me
def some_function(somearg)

some_function(arg)

I've been looking online about what I think is going on, and from what
I can tell this code is using function decorators.

I guess what I'm asking is if someone could tell me what exactly is
going on in this code - how is it different from passing:
time_me(some_function(123))? I've tried it this way and it works.

why would I use these? wouldn't it be more flexible to not write the
decorator before the function definition, so I could choose to wrap it
or not?

thanks
 
S

Seebs

why would I use these? wouldn't it be more flexible to not write the
decorator before the function definition, so I could choose to wrap it
or not?

The utility is that it lets you modify all calls to a function at once,
without changing all the instances in a ton of source code.

-s
 
D

Diez B. Roggisch

Nick Donohue said:
I came across this code just now:

def time_me(function):
def wrap(*arg):
start = time.time()
r = function(*arg)
end = time.time()
print "%s (%0.3f ms)" %(function.func_name, (end-start)*1000)
return wrap

@time_me
def some_function(somearg)

some_function(arg)

I've been looking online about what I think is going on, and from what
I can tell this code is using function decorators.

I guess what I'm asking is if someone could tell me what exactly is
going on in this code - how is it different from passing:
time_me(some_function(123))? I've tried it this way and it works.

This is *not* what the decorator is doing. The equivalent of a decorator
and then calling the result is this:

Notice the difference? The decorator (a badly written one, by the way -
it doesn't deal with a possible return value and keyword args) wraps the function
into time measuring code.

In general, a decorator is a callable that takes one argument. And
whatever that callable returns is then bound under the same name as the
original function (or class, since python 2.6 I believe)

Which is what

actually does. So decorator syntax with the @ is really just that - a
bit of syntactic sugar.

why would I use these? wouldn't it be more flexible to not write the
decorator before the function definition, so I could choose to wrap it
or not?

Of course it's more flexible to do whatever the decorator does only if
you need it. If you need that, it's a sign of a misuse of decorators.

Their strength is in making boiler-plate code run without you having to
type it out all the time.

E.g. putting transactional boundaries around some code that deals with a
database. Checking for proper authentication and
authorization. Uniformely deal with exceptions. And so forth.

Amongst the more popular decorators in python are the classmethod and
property decorators. Go look them up in the stdlib.


Diez
 
T

Terry Reedy

I came across this code just now:

def time_me(function):
def wrap(*arg):
start = time.time()
r = function(*arg)
end = time.time()
print "%s (%0.3f ms)" %(function.func_name, (end-start)*1000)
return wrap

@time_me
def some_function(somearg)

As others noted, this is an bad example of a decorator. Please forget
it. Let us move on...

#deco
def func_name(*args): pass

is syntactic sugar for (which is to say, is almost and for practical
purposes is exactly equivalent to)

def func_name(*args): pass
func_name = deco(func_name)

Indeed, Python did well without them until they were added. But there
are 2 advantages of the decorator syntax:

1. Without it, one write (and read!) func_name 3 times instead of 1. One
of the use cases that motivated decorators was a situation where someone
was required to wrap numerous functions with stylized names about 30
chars long, like 'get_hopscotch_version_a_code_123x76'

2. Understanding the code may require that one know that it will never
see the light of day as is. If the body is several lines, the wrapping
call may be hard to see. To put it another way, the wrapping calls often
belong near the doc string since they are part of a high-level overview
of the function.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Members online

No members online now.

Forum statistics

Threads
473,768
Messages
2,569,575
Members
45,053
Latest member
billing-software

Latest Threads

Top