Useful Decorators

This absolutely excellent talk by James Powell prompted this. It’s entirely worth the watch.

I hope to add more functions as time goes on

Why Use Decorators

Decorators allow you to quickly extend a function by wrapping it in a another function. This is useful for a number of reasons – pherhaps you want to occasionally log details about a function to file, or log the execution time of a function. You can add this code directly, but if you have several functions to add, it’s repetitive and annoying. Doing this with decorators saves you time and effort, and is easier to understand too!

Timer function

Note that their are two commonly used built in decorators, @classmethod and @staticmethod. I won’t really talk about them now, but this is a decent summary.

This is a decorator, called timer. Inside, a wrapper, called f, is defined. Inside f, I start a timer (before = time.perf_counter()), call the function I want to time (rv = func(*args, **kwargs)), then print the time elapsed ( print(f"Time Elapsed for {func.__name__} is {after - before} seconds")). That’s it.

import time

def timer(func):
    def f(*args, **kwargs):
        before = time.perf_counter()
        rv = func(*args, **kwargs)
        after = time.perf_counter()
        print(f"Time Elapsed for {func.__name__} is {after - before} seconds")
        return rv
    return f

*args, **kwargs allow me to pass thru arbirtary arguments to func from the wrapper, while func.__name__ accesses the function name nicely.

To use this on a function like

def printHello(myname):
    print(f"Hello {myname}!")

all that is required is

@timer
def printHello(myname):
    print(f"Hello {myname}!")

Now something like

printHello("ethan")

returns

My name is ethan
Time Elapsed for printHello is 0.00038960000000000383 seconds

2020