Have you ever wanted to add extra functionality to a function like logging, timing, or permission checks without actually changing the code inside that function? That is exactly what Decorators do. They allow you to "wrap" another function to extend its behavior.
π Decorators are a key part of writing clean, reusable, and "DRY" (Don't Repeat Yourself) Python code.
1. Analogy: The Phone Case
Think of your function as a Smartphone. It has core features like calling and texting. A Decorator is like a Phone Case.
The case doesn't change how the phone's internal circuits work, but it adds new "superpowers" like a kickstand, extra battery life, or water protection.
You can put the same case on different phones!
2. How it Works: Functions are Objects
In Python, functions are "first-class objects." This means you can:
- Assign a function to a variable.
- Pass a function as an argument to another function.
- Return a function from another function.
A decorator is simply a function that takes another function, adds some logic, and returns a new, "wrapped" version of it.
3. The
@ SyntaxInstead of writing
say_hello = my_decorator(say_hello), Python gives us a beautiful shortcut: the @ symbol. Placing @decorator_name above a function automatically wraps it.π Practical Code Example: A Simple Timer
Let's create a decorator that measures how long a function takes to run.
import time
# 1. Define the decorator
def timer_decorator(func):
def wrapper(*args, **kwargs): # The 'wrapper' adds the new behavior
start_time = time.time()
result = func(*args, **kwargs) # Execute the original function
end_time = time.time()
print(f"β±οΈ {func.__name__} took {end_time - start_time:.4f} seconds.")
return result
return wrapper
# 2. Use the decorator
@timer_decorator
def heavy_computation():
print("Computing...")
time.sleep(1.5) # Simulate a long task
print("Done!")
# 3. Call the function
heavy_computation()
4. Why Use Decorators?
- Code Reusability: Write the logic once (like logging) and apply it to 50 different functions.
- Separation of Concerns: Keep your main logic clean. The "extra" stuff (security, timing) stays in the decorator.
- DRY Principle: Prevents you from copy-pasting the same setup/teardown code into every function.
π― Today's Goal (What you should do)
βοΈ Understand that decorators "wrap" functions to add functionality
βοΈ Master the
@ syntax for applying decoratorsβοΈ Learn how to pass arguments to wrapped functions using
*args and *kwargsβοΈ Identify common use cases: Logging, Timing, and Authentication