Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Python > function decorators

Reply
Thread Tools

function decorators

 
 
Nick Donohue
Guest
Posts: n/a
 
      09-28-2010
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
 
Reply With Quote
 
 
 
 
Seebs
Guest
Posts: n/a
 
      09-28-2010
On 2010-09-28, Nick Donohue <(E-Mail Removed)> wrote:
> 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
--
Copyright 2010, all wrongs reversed. Peter Seebach / http://www.velocityreviews.com/forums/(E-Mail Removed)
http://www.seebs.net/log/ <-- lawsuits, religion, and funny pictures
http://en.wikipedia.org/wiki/Fair_Game_(Scientology) <-- get educated!
I am not speaking for my employer, although they do rent some of my opinions.
 
Reply With Quote
 
 
 
 
Diez B. Roggisch
Guest
Posts: n/a
 
      09-28-2010
Nick Donohue <(E-Mail Removed)> writes:

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

>>> some_function = time_me(some_function)
>>> some_function(123)


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

>>> some_function = time_me(some_function)


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
 
Reply With Quote
 
Terry Reedy
Guest
Posts: n/a
 
      09-29-2010
On 9/28/2010 6:02 PM, Nick Donohue wrote:
> 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.

--
Terry Jan Reedy

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
call 'the following function' using decorators castironpi@gmail.com Python 5 02-17-2008 08:43 PM
Radical: listing decorators compared to atexit function registration Bengt Richter Python 0 08-25-2004 08:26 PM
PEP 318 decorators are not Decorators Arien Malec Python 11 08-16-2004 06:38 PM
decorators: what's wrong with 'def [decorator-list] function-name (arguments)' Porky Pig Jr Python 0 08-14-2004 10:09 PM
decorators, function signature, and help() Peter Otten Python 1 08-10-2004 01:43 PM



Advertisments