Python Decorator Example (Simple Use Case)
If you are new to decorators, the easiest way to understand them is to see one small example that works.
This page shows a simple decorator that wraps a function, runs code before and after it, and helps you see why decorators are useful. It does not try to cover every decorator pattern.
Page goal #
This example focuses on one clear idea:
- Understand a simple decorator by example
- Read the code step by step
- Run it yourself and see the output
If you want the full beginner explanation later, see Decorators in Python: beginner introduction.
A simple runnable decorator example #
def show_before_after(func):
def wrapper():
print("Before function runs")
func()
print("After function runs")
return wrapper
@show_before_after
def say_hello():
print("Hello!")
say_hello()
This is the main pattern to notice:
show_before_aftertakes a function as input- It defines a new function called
wrapper wrapperruns extra codewrapperalso calls the original function- The decorator returns
wrapper
What the example shows #
This one example teaches the basic decorator idea:
- A decorator takes a function
- It returns a new function
- The new function runs extra code before and after the original function
- The
@decorator_namesyntax is a shortcut
If you already understand what a function is in Python, this pattern will make more sense.
How to read the code step by step #
1. Define the decorator #
def show_before_after(func):
This creates a decorator function.
The parameter func is the function being decorated.
2. Define wrapper() inside the decorator #
def wrapper():
This inner function is the new function that will replace the original one.
3. Run code before the original function #
print("Before function runs")
This is extra behavior added by the decorator.
4. Call the original function #
func()
This runs the original function that was passed into the decorator.
Be careful here:
funcmeans the function itselffunc()means “run the function”
5. Run code after the original function #
print("After function runs")
This is another piece of added behavior.
6. Return wrapper #
return wrapper
This is a very important line.
It means the decorator gives back the new wrapped function.
If you forget this line, the decorator will not work correctly.
7. Apply the decorator with @show_before_after #
@show_before_after
def say_hello():
print("Hello!")
This is a shorter way to write:
def say_hello():
print("Hello!")
say_hello = show_before_after(say_hello)
Both versions do the same thing.
8. Call the decorated function normally #
say_hello()
Even though say_hello was decorated, you still call it like a normal function.
If you need a refresher, see Python functions explained or how to create a simple function in Python.
Expected output #
When you run the code, you should see:
Before function runs
Hello!
After function runs
That output shows the order clearly:
- The decorator runs code before
- The original function runs
- The decorator runs code after
Why beginners use decorators #
Beginners usually meet decorators when they want to add repeated behavior without rewriting the same code again and again.
A decorator can help you:
- Add messages before or after a function runs
- Log information
- Time how long a function takes
- Check permissions or access
- Reuse the same pattern across many functions
The big benefit is this:
- You do not need to change the original function body each time
- You avoid copying the same extra code into many functions
Important limitation of this simple example #
This example is intentionally basic.
It only works with functions that take no arguments.
For example, this version works:
@show_before_after
def say_hello():
print("Hello!")
But this version would fail:
@show_before_after
def greet(name):
print(f"Hello, {name}!")
Why? Because wrapper() does not accept any parameters.
A more flexible decorator uses *args and **kwargs, but that is better explained on a dedicated lesson page. For the full beginner explanation, see Decorators in Python: beginner introduction.
Common beginner confusion #
These points often cause confusion:
- The decorator runs when the function is defined, not only when it is later called
wrapperis the function that replaces the original name- The original function still exists as
funcinside the wrapper
In simple terms:
- Before decoration,
say_hellorefers to the original function - After decoration,
say_hellorefers towrapper - Inside
wrapper,funcstill points to the originalsay_hello
You can inspect that a little with:
print(say_hello)
print(type(say_hello))
help(say_hello)
And to run your file:
python your_script.py
Common mistakes #
Here are some common problems beginners run into.
Forgetting to return wrapper #
Wrong:
def show_before_after(func):
def wrapper():
print("Before function runs")
func()
print("After function runs")
This is missing:
return wrapper
Without returning wrapper, the decorated function will not be set up correctly.
Forgetting to call func() inside wrapper #
Wrong:
def show_before_after(func):
def wrapper():
print("Before function runs")
print("After function runs")
return wrapper
This prints the messages, but it never runs the original function.
Adding the decorator but never calling the function #
This code defines the function:
@show_before_after
def say_hello():
print("Hello!")
But nothing happens until you call:
say_hello()
Using a wrapper with no parameters on a function that needs arguments #
This will cause a problem:
@show_before_after
def greet(name):
print(f"Hello, {name}!")
greet("Sam")
Your wrapper has no parameters, so it cannot accept "Sam".
Mixing up func and func() #
Remember:
func= the function objectfunc()= run the function
That small difference matters a lot in Python.
FAQ #
What is the simplest way to describe a decorator? #
A decorator is a function that changes or extends another function.
Do I need decorators as a beginner? #
Not at first, but a simple example helps you understand code you may see in real projects.
Why use @show_before_after instead of say_hello = show_before_after(say_hello)? #
They do the same thing. The @ syntax is shorter and easier to read.
Why does my decorator fail when my function has parameters? #
Your wrapper probably does not accept arguments. Use a wrapper that accepts *args and **kwargs.