Chapter 10: Advanced Topics / Lesson 55

Decorators

Introduction to Decorators

Decorators are a powerful Python feature that allows you to modify or extend the behavior of functions without permanently modifying them. Decorators use the @ symbol and are placed above function definitions.

Decorators are functions that take another function as an argument and return a modified version of that function. They're useful for adding functionality like logging, timing, or access control.

Basic Decorator

A decorator is a function that wraps another function:

basic_decorator.py
# Define a decorator def my_decorator(func): def wrapper(): print("Before function call") func() print("After function call") return wrapper # Use decorator @my_decorator def say_hello(): print("Hello!") say_hello() # Output: # Before function call # Hello! # After function call # Without @ syntax (equivalent) def say_hi(): print("Hi!") say_hi = my_decorator(say_hi) say_hi()

Decorators with Arguments

Decorators can work with functions that have arguments:

decorator_args.py
# Decorator for functions with arguments def smart_decorator(func): def wrapper(*args, **kwargs): print("Function called") result = func(*args, **kwargs) print("Function completed") return result return wrapper @smart_decorator def add(a, b): return a + b result = add(5, 3) print(result) # 8 # Timing decorator import time def timer(func): def wrapper(*args, **kwargs): start = time.time() result = func(*args, **kwargs) end = time.time() print(f"Function took {end - start:.4f} seconds") return result return wrapper

Common Use Cases

Decorators are commonly used for:

  • Logging function calls
  • Timing function execution
  • Input validation
  • Caching results
  • Access control and authentication

Built-in Decorators

Python provides some built-in decorators:

builtin_decorators.py
# @staticmethod and @classmethod (we learned these) class MyClass: @staticmethod def my_static_method(): print("Static method") # @property - makes a method act like an attribute class Circle: def __init__(self, radius): self._radius = radius @property def radius(self): return self._radius

Best Practices

✅ Decorator Tips

• Use decorators to add cross-cutting concerns

• Keep decorators simple and focused

• Use *args and **kwargs for flexibility

• Document what your decorator does

• Don't overuse decorators - they can make code harder to read

🎉

Lesson Complete!

Great work! Continue to the next lesson.

main.py
📤 Output
Click "Run" to execute...