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_after takes a function as input
  • It defines a new function called wrapper
  • wrapper runs extra code
  • wrapper also 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_name syntax 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:

  • func means the function itself
  • func() 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:

  1. The decorator runs code before
  2. The original function runs
  3. 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
  • wrapper is the function that replaces the original name
  • The original function still exists as func inside the wrapper

In simple terms:

  • Before decoration, say_hello refers to the original function
  • After decoration, say_hello refers to wrapper
  • Inside wrapper, func still points to the original say_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 object
  • func() = 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.

See also