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
Program¶
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)
Program 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