6: Decorators¶
Summary¶
- Decorators are functions that take a single function as an argument and return a single function
They are used to transform functions
A decorator is written as @dec in front of a function definition and that is equivalent to f = dec(f) where f is the name of the function
Some decorators modify the unction by returning a new wrapper function object
Some decorators add or modify attributes of the function object and do not return a new function object
Multiple decorators are applied starting with the decorator closest to the function working up the page
- You can also use a decorator factory with parameters
It is evaluated at once and has to return a decorator, which is applied to the function in the usual way
The main use of a decorator factory is to provide parameters to a decorator
- Decorators that return wrappers are more complicated because they change the function object
The standard wraps method can be used to transfer attributes from the original function object to the new object
Basic Decorator¶
# Decorator = a function that extends the behavior of another function
# with out modifying the base function
def add_sprinkles(func): # a decorator needs a function passed to it
def wrapper(*args, **kwargs): # an inner function
print("You add sprinkles") # decorating the function by adding to it
func(*args, **kwargs) # calling the function that was passed
return wrapper # returns the inner function
def add_fudge(func):
def wrapper(*args, **kwargs): # accepts any number of arguments and keyword arguments (future proof)
print("You add fudge")
func(*args, **kwargs)
return wrapper
@add_sprinkles
@add_fudge
def get_ice_cream(flavor):
print(f"Here is your {flavor} Ice cream")
get_ice_cream("vanilla")
Basic Decorator Output¶
You add sprinkles
You add fudge
Here is your vanilla Ice cream
Complex Decorator¶
from functools import wraps
# ---------------------------------------
# 1️⃣ Simple decorator (returns wrapper)
# ---------------------------------------
def simple_logger(func):
"""Decorator that wraps a function and logs before calling it."""
@wraps(func) # preserves original function metadata
def wrapper(*args, **kwargs):
print(f"Calling function: {func.__name__}")
return func(*args, **kwargs)
return wrapper
# ---------------------------------------------------
# 2️⃣ Decorator that modifies attributes (no wrapper)
# ---------------------------------------------------
def add_author(func):
"""Decorator that adds an attribute to the function."""
func.author = "Brayden"
return func # returns same function object
# ---------------------------------------
# 3️⃣ Decorator factory (takes parameter)
# ---------------------------------------
def repeat(times):
"""Decorator factory that repeats function execution."""
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
for _ in range(times):
result = func(*args, **kwargs)
return result
return wrapper
return decorator # must return a decorator
# ---------------------------------
# 4️⃣ Using multiple decorators
# Closest decorator runs first
# ---------------------------------
@add_author
@simple_logger
@repeat(2)
def greet(name):
"""Greets a person."""
print(f"Hello {name}!")
# ---------------------------------
# Main Program
# ---------------------------------
greet("Alice")
print("\nFunction name:", greet.__name__)
print("Author attribute:", greet.author)
Complex Decorator Output¶
(docs-env) root@BMitchellLTOP:~/git/sphinx_students/source/programming_lang/book/programs# python3 chapterSix.py
Calling function: greet
Hello Alice!
Hello Alice!
Function name: greet
Author attribute: Brayden