Date: February 12th 2016
Last updated: February 9th 2017

This entry follows on from closures because they are the main underlying concept of decorators. Things to remember while considering decorators include scoping rules and nested functions. Also recall that functions can be passed as arguments to other functions, and a function can be returned.

I recommend reading the section on "returning functions" by Jeff Knupp. For a concise explanation of decorators read this article and the go on to read this article. There is a repository containing python decorators here.

Useful resources:

Basic structure:
The "@" symbol followed by the function name is used to implement the decorator. The decorator must be called immediately before the decorated function.

def wrapper(func):
    def main_function_call(*args):
        # modify some code
        # print some stuff
        # log some stuff etc
        # execute the function
        return func(*args)
    return main_function_call

# syntact sugar version of decorator
def new_func():
    # add some code

# the decoratation symbol is the same as this:
new_func = wrapper(new_func)


Logging decorator:

import logging

def logger(func): #func is a callable
    # instantiate logging module
    logger = logging.getLogger(__name__)

    def inner(*args, **kwargs):'logging inner function')
        return func(*args, **kwargs)  #returns a callable

    return inner

def add(x, y):
    """docstring: add 2 arguments together"""
    return x + y

print("@logger: add(2,2) = %s \n" %add(2, 2))
print("@logger: add(2,4) = %s \n" %add(2, 4))

# returns:
#INFO:__main__:logging inner function
#@logger: add(2,2) = 4 
#INFO:__main__:logging inner function
#@logger: add(2,4) = 6

Check docstrings decorator:

def doccheck(f):
    if f.__doc__:
        print("%s" % f.__doc__)
    return f

def add(x, y):
    """docstring: add 2 arguments together"""
    return x + y

print("@doccheck: add(2,2) = %s \n" %add(2, 2))

# returns:
#docstring: add 2 arguments together
#@doccheck: add(2,2) = 4

strip argument decorator: use one argument

def strip_arg(func):
    def inner(*args):
        # isolate x argument
        x = args[0]
        # only x makes it to the function call
        # this makes add function use default y value
        return func(x)
    return inner

def add(x, y=7):
    """docstring: add 2 arguments together"""
    return x + y

print("@strip_arg: add(2) = %s " %add(2))
print("@strip_arg: add(2,2) = %s " %add(2,2))
print("@strip_arg: add(2,8) = %s \n" %add(2,8))

# returns:
#@strip_arg: add(2) = 9 
#@strip_arg: add(2,2) = 9 
#@strip_arg: add(2,8) = 9

Currency decorator: adapted from here

def currency(f):
    def wrapper(f):
        return '$' + str(f)
    return wrapper

def price(value):
    return value

#returns: $9

results matching ""

    No results matching ""