Skip to content

Instantly share code, notes, and snippets.

@jcfrank
Last active August 29, 2015 14:03
Show Gist options
  • Save jcfrank/9c2f3b4d4bd2d6ec44b7 to your computer and use it in GitHub Desktop.
Save jcfrank/9c2f3b4d4bd2d6ec44b7 to your computer and use it in GitHub Desktop.
Python decorator pattern

Desc

Unlike java, python uses nested functions to implement decorators.

This could be tricky when we first try to understand.

A few features of python are applied:

  1. python functions are objects.
  2. nested function defines are allowed.
  3. functions can return function objects.

Sample code

Decorator functions without arguments are different with functions with argument.

Notice the differences in following code:

def simpledecorator(func):
    print("This function is decorated with a decorator with no argument.")
    def actual(*args, **kwargs):
        return func(*args, **kwargs)
    return actual

"""
Followings are the same as:
def simpleprint(message):
    print("Hello %s" % message)

simpledecorator(simpleprint)("simple decorator!")
"""
@simpledecorator
def simpleprint(message):
    print("Hello %s" % message)

simpleprint("simple decorator!")

print("\n========\n")

def decorator_with_args(arg1, arg2):
    def innerdecorator(func):
        print("This function is decorated with with a decorator with argument %s, %s" % (arg1, arg2))
        def actual(*args, **kwargs):
            return func(*args, **kwargs)
        return actual
    return innerdecorator

"""
Followings are the same as:
def print_again(message):
    print("Hello %s" % message)

decorator_with_args(arg1, arg2)(print_again)("decorator with arguments!")
"""
@decorator_with_args("a1", "a2")
def print_again(message):
    print("Hello %s" % message)

print_again("decorator with arguments!")

output:

This function is decorated with a decorator with no argument.
Hello simple decorator!

========

This function is decorated with with a decorator with argument a1, a2
Hello decorator with arguments!

Real life sample

Product Price
Coffee $25
Add milk $25
Add cinnamon $10

How much is a cup of coffee, add milk, add cinnamon cost?

def add_milk(func):
    def actual(*args, **kwargs):
        return func(*args, **kwargs) + 25
    return actual

def add_cinnamon(func):
    def actual(*args, **kwargs):
        return func(*args, **kwargs) + 10
    return actual

@add_milk
@add_cinnamon
def buy_mixed_coffee():
    return 50

price = buy_mixed_coffee()
print("mixed price: %s" % price)

# add milk again
price = add_milk(buy_mixed_coffee)()
print("double milk price: %s" % price)

# the same as buy_mixed_coffee
def buy_coffee():
    return 50

price = add_milk(add_cinnamon(buy_coffee))()
print("mixed price: %s" % price)

output:

mixed price: 85
double milk price: 110
mixed price: 85
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment