views:

285

answers:

3

In this blog article they use the construct:

  @measured
  def some_func():
    #...
  # Presumably outputs something like "some_func() is finished in 121.333 s" somewhere

This @measured directive doesn't seem to work with raw python. What is it?

UPDATE: I see from Triptych that @something is valid, but is where can I find @measured, is it in a library somewhere, or is the author of this blog using something from his own private code base?

+3  A: 
Triptych
A: 

measured is the name of a function that must be defined before that code will work.

In general any function used as a decorator must accept a function and return a function. The function will be replaced with the result of passing it to the decorator - measured() in this case.

recursive
You terminology is confusing. Generators, in particular, have a very precise definition in Python. Also, while it's true that measured must be defined, that doesn't really explain what it does.
Triptych
Bah, yes. Quite right. It's a decorator, not a generator. Typo corrected. I've just got generators on the brain today.There's no way to know what it does from the excerpt given, so I'm not sure that it's possible to explain what it does.
recursive
Cool - removed my downvote.
Triptych
+12  A: 

@measured decorates the some_func() function, using a function or class named measured. The @ is the decorator syntax, measured is the decorator function name.

Decorators can be a bit hard to understand, but they are basically used to either wrap code around a function, or inject code into one.

For example the measured function (used as a decorator) is probably implemented like this...

import time

def measured(orig_function):
    # When you decorate a function, the decorator func is called
    # with the original function as the first argument.
    # You return a new, modified function. This returned function
    # is what the to-be-decorated function becomes.

    print "INFO: This from the decorator function"
    print "INFO: I am about to decorate %s" % (orig_function)

    # This is what some_func will become:
    def newfunc(*args, **kwargs):
        print "INFO: This is the decorated function being called"

        start = time.time()

        # Execute the old function, passing arguments
        orig_func_return = orig_function(*args, **kwargs)
        end = time.time()

        print "Function took %s seconds to execute" % (end - start)
        return orig_func_return # return the output of the original function

    # Return the modified function, which..
    return newfunc

@measured
def some_func(arg1):
    print "This is my original function! Argument was %s" % arg1

# We call the now decorated function..
some_func(123)

#.. and we should get (minus the INFO messages):
This is my original function! Argument was 123
# Function took 7.86781311035e-06 to execute

The decorator syntax is just a shorter and neater way of doing the following:

def some_func():
    print "This is my original function!"

some_func = measured(some_func)

There are some decorators included with Python, for example staticmethod - but measured is not one of them:

>>> type(measured)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'measured' is not defined

Check the projects import statements to see where the function or class is coming from. If it uses from blah import * you'll need to check all of those files (which is why import * is discouraged), or you could just do something like grep -R def measured *

dbr
I take it measured is not a standard function, but thanks for writing one for me!
Tristan Havelick
haha wow. Kudos on the extra effort.
Triptych
Thank you for the example and explanation.
ayaz
I notice that function arguments are not mentioned in the example code, does that mean they're handled "correctly" by Python automatically?
unwind
I've been looking for a good explanation of descriptors and this one did it for me. Thanks
Michael Groner
unwind: Good point, I forgot about arguments. Fixed code to pass all arguments to "wrapped" function
dbr