Python Decorators in 5 Easy Steps (With Simple Code Examples)
In Python, a decorator is like a wrapper around a function. You add it on top of a function using @ syntax, and it lets you do something extra every time that function runs—without changing the original code. Sounds confusing? Let’s break it down in 5 simple steps so it clicks.
🧠 Step 1: Functions Are Objects
Functions in Python can be treated like variables. You can assign a function to another variable and call it from there.
def recipe():
print("this is my recipe")
my_recipe = recipe
my_recipe()
Explanation: my_recipe = recipe copies the function (not its result), and my_recipe() executes it. This is the foundation for decorators.
🧁 Step 2: Functions Inside Functions
You can define one function inside another. This lets you group logic and control scope.
def outer():
def inner():
print("I'm the inner function!")
inner()
my_outer = outer
my_outer()
Explanation: inner() exists only within outer(). When you call outer(), it runs inner(). In this example, we assign outer to my_outer (as a function object), and then call it with my_outer(). This shows how nested functions can be executed from outside their definition block, and this nesting is key to how decorators work.
🧁 Step 3: Functions Returning Functions
Functions can return other functions—this lets us customize behavior dynamically.
def outer():
def inner():
print("Hello from inner!")
return inner
my_func = outer()
my_func()
Explanation: outer() returns inner (not executed), and my_func() then executes it. This lets us create decorators that return a new function that wraps the original.
🧁 Step 4: Passing Functions to Functions
Functions can take other functions as arguments. These are often called callbacks.
def greet(func):
print("Doing something first...")
func()
def say_hi():
print("Hi!")
greet(say_hi)
Explanation: We pass say_hi into greet, which then calls it. This is another essential idea behind decorators—they accept a function, modify its behavior, and return a new version.
🧁 Step 5: Making Your First Decorator!
This is the real deal. Here's your first decorator in action:
def my_decorator(func):
def wrapper():
print("Before the function runs")
func()
print("After the function runs")
return wrapper
@my_decorator
def say_hello():
print("Hello!")
say_hello()
Explanation: The @my_decorator line means Python runs say_hello = my_decorator(say_hello) behind the scenes. This replaces say_hello with the wrapper function that calls the original one, with extra steps before and after.
say_hello = my_decorator(say_hello)
say_hello()
✨ Why Use Decorators?
- Logging
- Timing
- Authentication
- Validation
- Keeping code DRY (Don’t Repeat Yourself)
Decorators are powerful tools for enhancing functions without modifying their internals.
🎥 Watch the Full Tutorial
Prefer to learn by watching? Check out the full step-by-step video tutorial on my YouTube channel: