Ricky Wilson
Ricky Wilson

Reputation: 3359

Python: How can i convert this into a decorator

I cant't for the life of me figure out how to make this into a decorator. Any help or an example would be awesome.

Here is the code

import datetime    

def time_func(function, *args, **kwargs):
  '''
  Add the execution time to a functions attributes 
  '''
  # Start the clock.
  start = datetime.datetime.now()
  # Execute the function and record the results.
  function_result = function(*args, **kwargs)
  # Calculate the elapsed time and add it to the function
  # attributes.
  function.elapsed = datetime.datetime.now() - start
  # Returned the function with the added elapsed attribute 
  return function_result

Here is an example use

.. import datetime 
..  
..  
.. def time_func(function, *args, **kwargs): 
..   ''' 
..   Add the execution time to a functions attributes  
..   ''' 
..   # Start the clock. 
..   start = datetime.datetime.now() 
..   # Execute the function and record the results. 
..   function_result = function(*args, **kwargs) 
..   # Calculate the elapsed time and add it to the function 
..   # attributes. 
..   function.elapsed = datetime.datetime.now() - start 
..   # Returned the function with the added elapsed attribute  
..   return function_result 
..    
..  
.. def f(name): 
..   print name 
..    
.. time_func(f, 'foo') 
.. print f.elapsed 
.. 
foo
0:00:00.000115

Upvotes: 0

Views: 1426

Answers (3)

Blckknght
Blckknght

Reputation: 104712

A common way to make decorators is to use two nested functions:

def time_func(function):
  def wrapper(*args, **kwargs):
      start = datetime.datetime.now()
      function_result = function(*args, **kwargs)
      wrapper.elapsed = datetime.datetime.now() - start
      return function_result
   return wrapper

The only major between this code and your original (other than stripping out the comments for space) is that the function is supplied by a call to the outer function while the other arguments are supplied to the wrapper function. We also need to save the elapsed time on the wrapper function instead of the original function (since the original will not be accessible any more when you a decorator).

Upvotes: 0

user2124834
user2124834

Reputation:

A decorator is simply a function that takes a function and returns a function.

import datetime

def time_func(function):
    # create a new function based on the existing one,
    # that includes the new timing behaviour
    def new_func(*args, **kwargs):
        # Start the clock.
        start = datetime.datetime.now()
        # Execute the function and record the results.
        function_result = function(*args, **kwargs)
        # Calculate the elapsed time and add it to the function
        # attributes.
        new_func.elapsed = datetime.datetime.now() - start
        # Returned the function with the added elapsed attribute 
        return function_result
    return new_func

Usage:

@time_func
def f(name):
    print(name)

f('foo')
print(f.elapsed)
> foo
> 0:00:00.000045

Check out functools.wraps to further improve the decorator.

Upvotes: 2

Daniel
Daniel

Reputation: 42758

Define an inner function:

import datetime    

def time_func(function):
    '''
    Add the execution time to a functions attributes 
    '''
    def func(*args, **kwargs):
        start = datetime.datetime.now()
        function_result = function(*args, **kwargs)
        func.elapsed = datetime.datetime.now() - start
        return function_result
    return func

@time_func
def f(name):
    print name

Upvotes: 2

Related Questions