https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_b964594d3d957944241961017b9eb19bf02834de44cce93d8e67dd306852dbe346167181e455e33d5268ea01d973d77bb056848546f31794f31a4c31a9da5aa3.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_23f1ae74c634d7e5e0a067c22b7a8c2d79c3ffd9a3b9395fc82c1b3b99635552b994f1f72f532f28ceaff1ea054ea026cd488cd62fa03a4ad91d212b5f3c5a72.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_451c3884f51125f7687e5bb07cfab033c04cb7174c33f93213b2af4bad2af13cf48b92a7fa95fc86d7d436f355938a3ac50aa119cdb7c9b6d5a52815c3e6033e.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_bfff9e63e857e9ee612e292d4a6edf3ced64d6a756925c953a9d8f77845ff601eca64d73dfa48756b1a9f4a4d6de6127a273bcde16ddeb71a22383460f4e94b0.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_f4dd7e1d73ae5eda35ed5ad6aa965b612dbf483ece3ca50c1e8e30ad8dff1c66a160ed75e958e2db399661d229874783e0834ad813a479437035666b8e9e3386.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_4fce0769137d4cd096989b0349bc3c2bbfca79ac311fdf714c41ab24d87551c7b49b756c8a8de090b0714a0ad0560e49fa532ba5a88875ea4afd78efac464df6.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_85cec8b07d60426b11040e471babca0d2f9c8dc87a9b56e06cad39828f7f67179e29609100f282a574872c9a93fb635b25416300eb4c97bc5a653d00cf6f8dbf.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_6768e5a27d4d357347338621c0d20bd269b126d30eec796193390f2f530fbaea60af84130c46f9786114be65149e661e87d55c339219c90aa76396d7e5b734ef.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_2acd6bdff3b680341e8c727da5169a647123eb8fd0a90253161b4c3af272c15d293bf9bb217008bb13f84d1910b0e166798001f8603b6c026d5c20a76c41d47c.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_91d1a5a7e0f0f3d6002493b02c1177968675940579b5bbf60cf2a9d9436ac4a0e4fe777409355aa999bbad39ed34dd9a8946f7b899afac55c02abdd167cb1356.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_268c9bba6ba649318f0da28c37b09a9bbfa371210f9b6b52faa7fd8ae94abf6b3c3bfeb5df5705c93495ce1152ca58aeabc435d6c6c1bd959025165c3f50e086.js
  • Skip to main content
  • Skip to primary sidebar
  • Skip to footer
  • Home
  • Featured
    • Advanced Python Topics
    • AWS Learning Roadmap
    • JWT Complete Guide
    • Git CheatSheet
  • Explore
    • Programming
    • Development
      • microservices
      • Front End
    • Database
    • DevOps
    • Productivity
    • Tutorial Series
      • C# LinQ Tutorials
      • PHP Tutorials
  • Dev Tools
    • JSON Formatter
    • Diff Checker
    • JWT Decoder
    • JWT Generator
    • Base64 Converter
    • Data Format Converter
    • QR Code Generator
    • Javascript Minifier
    • CSS Minifier
    • Text Analyzer
  • About
  • Contact
CodeSamplez.com

CodeSamplez.com

Programming And Development Resources

You are here: Home / Programming / Python Decorators Tutorial: Examples, Use Cases & Best Practices

Python Decorators Tutorial: Examples, Use Cases & Best Practices

Updated June 1, 2025 by Rana Ahsan Leave a Comment ⏰ 7 minutes

Python Decorators Tutorial

Python decorators let you modify a function’s behavior without changing its code. For example, you can just use @decorator syntax to add logging or timing to any function.

In this tutorial, you’ll learn how decorators work, see some real-world code examples and know about some best practices to follow. If you’re new to decorators, buckle up; by the end of reading this article, you can use them like a pro.

Tip💡: Explore more advanced topics in Python like this.

What Are Decorators in Python?

Think of decorators as fancy gift wrappers for your functions. They allow you to take an existing function and extend its behaviour without modifying its source code. It’s like adding superpowers to your functions on demand!

In Python terms, decorators are just functions that modify other functions. They’re like powerful middleware that can execute code before and after the wrapped function runs. At a high level, decorators follow the decorator design pattern: they take a function, add some behaviour, and then return it.

In Python, they’re compelling because functions are first-class citizens, meaning you can pass them around and manipulate them like any other object.

Your First Decorator: Baby Step

Let’s start with something straightforward:

def my_first_decorator(func):
    def wrapper():
        print("Something is happening before the function")
        func()
        print("Something is happening after the function")
    return wrapper

@my_first_decorator
def say_hello():
    print("Hello!")

# When we call say_hello()...
say_hello()
# Output:
# Something is happening before the function
# Hello!
# Something is happening after the functionCode language: PHP (php)

💡 The @ syntax is just syntactic sugar! It’s the same as writing: say_hello = my_first_decorator(say_hello)

The Anatomy of a Python Decorator

Let’s break down the previous example and dive into step by step what’s happening:

  1. We define a function (my_first_decorator) that takes another function as an argument.
  2. Inside, we define a new function (wrapper) that calls the original function and modifies its result.
  3. We return this new wrapper function.
  4. When we use the @my_first_decorator Syntax, Python essentially does this behind the scenes:
Python Decorators Workflow Diagram during Program Execution

Core Decorator Types

Function Decorators

These are the most common type of decorators. They are used to modify or enhance functions or methods. A function decorator is a higher-order function that takes a function as an argument and returns a new function (or a modified version of the original).

Key Characteristics

  • Can modify arguments or return values
  • Wraps a single function or method.
  • Can add functionality before or after the original function’s execution.

Example:

Refer to the very first example we shared earlier in this guide.

Class Decorators: The Object-Oriented Approach

Class decorators are used to modify or enhance entire classes. A class decorator is a function that takes a class as an argument and returns a new class or a modified version of the original class.

Key Characteristics

  • Can be used for tasks like singleton creation or automatic registration of classes.
  • Wraps an entire class.
  • Can add or modify class attributes or methods.

Example:

class Cache
    def __init__(self):
        self.data = {}
    
    def __call__(self, func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            key = str(args) + str(kwargs)
            if key not in self.data:
                self.data[key] = func(*args, **kwargs)
            return self.data[key]
        return wrapper

@Cache()
def expensive_computation(n):
    print("Computing...")
    return n * n

print("First try:")
print(expensive_computation(10))
print("Second attempt:")
print(expensive_computation(10))

# Output
# First try:
# Computing...
# 100
# Second attempt:
# 100

Built-in Decorators

Python comes with several built-in decorators that provide common functionalities. These are often used to interact with classes and methods in specific ways.

@staticmethod decorator

Declares a static method within a class. Static methods don’t receive an implicit first argument (self or cls). They are bound to the class and not the instance of the class.

class MathUtils:
    @staticmethod
    def add(x, y):
        return x + y

print(MathUtils.add(5, 3)) # Output: 8Code language: CSS (css)

@classmethod decorator

Declares a class method. Class methods receive the class itself as the first argument, conventionally named cls. They can modify class state that applies across all instances of the class.

class Car:
    num_wheels = 4

    @classmethod
    def get_num_wheels(cls):
        return cls.num_wheels

print(Car.get_num_wheels()) # Output: 4

@property decorator

Used to create getter, setter, and deleter methods for a class attribute, allowing you to treat a method like an attribute.

class Circle:
    def __init__(self, radius):
        self._radius = radius

    @property
    def radius(self):
        print("Getting radius")
        return self._radius

    @radius.setter
    def radius(self, value):
        if value < 0:
            raise ValueError("Radius cannot be negative")
        print("Setting radius")
        self._radius = value

c = Circle(5)
print(c.radius) # Calls the getter
c.radius = 10   # Calls the setterCode language: HTML, XML (xml)

Levelling Up – Python Decorators with Arguments!

Python decorators can take arguments if you want it to. Here’s a simple example:

def repeat(times):
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            for _ in range(times):
                result = func(*args, **kwargs)
            return result
        return wrapper
    return decorator

@repeat(times=3)
def greet(name):
    print(f"Hello, {name}")

greet("Bob")
# Output:
# Hello, Bob
# Hello, Bob
# Hello, BobCode language: PHP (php)

Real-World Examples Of Python Decorators

Authentication Decorator

This is similar to what we can use to implement auth gatekeeping to some functions:

def require_auth(func):
    @wraps(func)
    def wrapper(request, *args, **kwargs):
        auth_token = request.headers.get('Authorization')
        if not auth_token:
            raise AuthError("No auth token provided")
        if not is_valid_token(auth_token):
            raise AuthError("Invalid token")
        return func(request, *args, **kwargs)
    return wrapper

@require_auth
def get_user_data(request):
    return {"user": "data"}Code language: JavaScript (javascript)

Decorator For Retry Mechanism:

Here’s another real-world use case for retry logic. It’s often useful in scenarios like microservices where networks can often be unreliable:

def retry(max_attempts=3, delay=1):
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            attempts = 0
            while attempts < max_attempts:
                try:
                    return func(*args, **kwargs)
                except Exception as e:
                    attempts += 1
                    if attempts == max_attempts:
                        raise e
                    time.sleep(delay)
            return None
        return wrapper
    return decorator

@retry(max_attempts=3, delay=2)
def unstable_network_call():
    # Simulated unstable API call
    passCode language: PHP (php)

Timing Decorator:

Here’s something I use all the time to profile my functions and optimize:

import time
from functools import wraps

def timer(func):
    @wraps(func)  # This preserves the original function's metadata
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        end = time.time()
        print(f"{func.__name__} took {end - start:.2f} seconds to run")
        return result
    return wrapper

@timer
def slow_function():
    """This is a slow function."""
    time.sleep(1)
    return "Done!"

print(slow_function())
# Output:
# slow_function took 1.00 seconds to run
# Done!Code language: PHP (php)

⚠️ Common Mistake Alert: Forgetting @wraps(func) will mess up your function’s metadata, causing headaches with testing and documentation tools.

Common Pitfalls And How to Avoid Them

Mutable Arguments in Decorators:

# DON'T DO THIS
def decorator(func):
    cache = []  # This is shared between all decorated functions!
    def wrapper():
        return func()
    return wrapper

# DO THIS
def decorator(func):
    def wrapper(cache=None):
        cache = cache or []  # New cache for each call
        return func()
    return wrapperCode language: PHP (php)

Decorators Order Matter in Python:

@decorator1
@decorator2
def function():
    pass

# Is equivalent to:
function = decorator1(decorator2(function))
# decorator1 executes after decorator2Code language: PHP (php)

Forgetting to Return the Wrapper:

If you forget to return wrapper in your decorator, it’ll break, likely with a NoneType error.

# Broken example - missing return statement
def broken_decorator(func):
    def wrapper():
        print("Doing something extra!")
        func()

@broken_decorator
def greet():
    print("Hello")

# This will raise an error when called
# greet()Code language: PHP (php)

Python Decorators Best Practices

You probably picked up a few ones already if you followed thoroughly so far. However, here’s a concise list of key best practices when working with decorators:

  • Always use @wraps , to help preserve metadata
  • Keep decorators focused on a single responsibility
  • Document what your decorators do
  • Consider making decorators optional with parameters
  • Test decorated functions both with and without the decorator

Conclusion

Decorators are like secret ingredients in your Python cookbook. They allow you to write cleaner, more modular code by separating concerns. Remember, the key to mastering decorators is practice. Start small, experiment, and soon you’ll be wrapping functions like a pro! Also, read more on official documentaiton as well.

Happy Python programming! 🐍✨

Share if liked!

  • Click to share on Facebook (Opens in new window) Facebook
  • Click to share on X (Opens in new window) X
  • Click to share on LinkedIn (Opens in new window) LinkedIn
  • Click to share on Pinterest (Opens in new window) Pinterest
  • Click to share on Reddit (Opens in new window) Reddit
  • Click to share on Tumblr (Opens in new window) Tumblr
  • Click to share on Pocket (Opens in new window) Pocket

You may also like


Discover more from CodeSamplez.com

Subscribe to get the latest posts sent to your email.

First Published On: November 19, 2024 Filed Under: Programming Tagged With: python

About Rana Ahsan

Rana Ahsan is a seasoned software engineer and technology leader specialized in distributed systems and software architecture. With a Master’s in Software Engineering from Concordia University, his experience spans leading scalable architecture at Coursera and TopHat, contributing to open-source projects. This blog, CodeSamplez.com, showcases his passion for sharing practical insights on programming and distributed systems concepts and help educate others.
Github | X | LinkedIn

Reader Interactions

Leave a ReplyCancel reply

Primary Sidebar

  • Facebook
  • X
  • Pinterest
  • Tumblr

Subscribe via Email

Top Picks

python local environment setup

Python Local Development Environment: Complete Setup Guide

In-Depth JWT Tutorial Guide For Beginners

JSON Web Tokens (JWT): A Complete In-Depth Beginners Tutorial

The Ultimate Git Commands CheatSheet

Git Commands Cheatsheet: The Ultimate Git Reference

web development architecture case studies

Web Development Architecture Case Studies: Lessons From Titans

static website deployment s3 cloudfront

Host Static Website With AWS S3 And CloudFront – Step By Step

Featured Dev Tools

  • JSON Formatter
  • Diff Checker

Recently Published

advanced service worker features

Advanced Service Worker Features: Push Beyond the Basics

service worker framework integration

Service Workers in React: Framework Integration Guide

service worker caching strategies

Service Worker Caching Strategies: Performance & Offline Apps

service worker lifecycle

Service Worker Lifecycle: Complete Guide for FE Developers

what is service worker

What Is a Service Worker? A Beginner’s Guide

Footer

Subscribe via Email

Follow Us

  • Facebook
  • X
  • Pinterest
  • Tumblr

Explore By Topics

Python | AWS | PHP | C# | Javascript

Copyright © 2025

https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_7ccdd7770abee97eba3c9a85c893b97e240722af6093aaac3dc42b8bc90424f318902f5504b6acc02b6d32c5d0ede3ee1b62e2cdb826acc6a2c4d15f53699262.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_c402e38f1879c18090377fb6b73b15ac158be453ecda3a54456494fe8aba42b990c293bae5424e5643d52515ffc2067e0819995be8d07d5bba9107a96780775c.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_ffc3511227531cc335353c54c3cbbaa11d0b80e5cb117478e144436c13cd05495b67af2e8950480ed54dbdabcdcef497c90fdb9814e88fe5978e1d56ce09f2cf.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_d57da9abfef16337e5bc44c4fc6488de258896ce8a4d42e1b53467f701a60ad499eb48d8ae790779e6b4b29bd016713138cd7ba352bce5724e2d3fe05d638b27.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_edc0e9ef106cc9ef7edd8033c5c6fcff6dc09ee901fd07f4b90a16d9345b35a06534f639e018a64baaf9384eee1df305570c1ecad747f41b787b89f53839962b.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_5a3aa28cd4eb24db3e3e2acd58230ff5cdc78120b94c2b118227d4c7806ecac03978e1a10404240314f66a3b82af8823768abb8b9eccc5003d198eb077ea12b8.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_dccc492dbbfdac33d1411f9df909e849c7268fcf99b43007f278cde3a0adc0ae00e8cae5ec81cf255b9a6eae74e239ba1fa935572af77173219cb081f7d2327d.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_00bacf9e36181aac2b666d110cd9d82257f846766e7041b2d7b3c909b458982931ccc9b203e37098fbdfcf43ca359cf04e3824a724a6789fc204196d3a72ad29.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_9ec67c9c17f4bd4ee02d35306a5bab19fdbef2a0fa3c6781f9fac40bcf7c642f79fefc0059051cc9082c8dece5be9cd4b37e2cf418ab5c3f4952d54517b24824.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_aa5a5d229b421633f4247380e1e8c0a4854f82efb35d13a5b07b7b8fbe22e98842a580f063e5965345a51c477a7f5c2585edf8dd7d896b2438dc61f91d8d970c.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_bb8058a9e234a7ffaa98891b1df7f6b8e67410e6984568b151daa05113b8c7f89d7b5918ae73f020998a16f7f5a087a13d6a9a5e5d7c301e2ca12fd9d1f8d177.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_647fb67570c6108fb10ae6785a1abdbecac99ffcf80351d0bef17c3cf783dce497b1895fcdaae997dacc72c359fbfb128cc1540dd7df56deb4961e1cd4b22636.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_f7a298a0f1f754623fe3b30f6910ce2c1373f715450750bd7a391571812b00df1917e2be90df6c4efc54dbdfda8616278a574dea02ba2c7a31992768df8db334.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_df30604d5842ef29888c3c1881220dc6d3f8854666d94f0680c5f38aa643c5fb79b10eb9f10998d8856eb24ca265783195937434fd6c2bb8e4846df0277a7fb7.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_f17fe6fb0993f1703181d7ae9e9ea570f3d33a43afd6f2a4567daa1a6745698c7b8193dc72d50991d2dd87cd3dcf663959206607d193a9b57926d061a1f50aef.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_945dcbab2c2a131f3c90f4fb91776b76066d589f84fb55bff25cd5d79a56218000616bfca1f0af9a74f32348693707af49e8fe624de8aa34f1e1c5b6a25709cf.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_65820d252e1b93596de6697fd5f02483f3e2524a0696c7d698b64745edb32bf5831a90e556842f5f88c8209766cc78ca3a41cf783d20236a9f90d4a7ea7b3e72.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_7286884797a1210857e2a36f8ab46604b0034b6abf512380447a5763c873db6a72b8547f660053de0ea69faef1eb64878f39ff4b0ea86c963efab95764a3bf5b.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_cbcf6c279ac6c6a25ae138bf964e64a5fd90d22dcdf8a53b6fe7b72cefa51063bfb0181a6e50dd2acdcae2795619887d1d83b10461e44e5103be756f2588d837.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_47965bc586b95810c925b9df3314e0c9a5cd121e70ca0831f87df0bc034695de4f83ecf2def86f737e14614ee138794473cf32cd3082a5d38db9dec0c1f266fa.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_12aa201cea075846d266536aa222d64d4088b851d87f55dac5e611b77add6826c8ebc6e82650fcd1a9e88a05a0072dedd195719c5f64cd4580a0acd8aee05d92.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_7859317dea28a85c983d7b2a933704b193600b52929d2d894deae21a5d78f1f9715214d4c2ed1b925e9183146806725621d586779705dea3b651260eb53a2f8a.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_dc8632457c35dcb14243a596dca1e1aecb827740c5b0305dbc37458f19dfaf3be1c94db5a7e9c620a813060998dfc86c16f5bbd77fd57618d4673c0580c0728a.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_d87ea86dd0e7ecdd5fe7a5bb67becf943e57c3add866b456034d51663d099031bd563e12f61fdccc044969adf938a8584ed22ccd401ab8b669e20e4f92fb54e8.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_35311c3d71a3605fad4e1d6b50f3911311cdcc46418bdf56d6d0308a75a69585269ee7582a335e29989adf308fa1a81a10a2c2d4e257e9d680447a4996f6269e.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_f4fc182ef03c12e9dcadd6febc3dbaa4a29134469057ca9e8ec0be2f2de29a494514ff4b59798e74debf26f78b2df2b3e2665c69b77035761fb463b783202915.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_85c0f2769456e60153b0fd8364b82a035da53384f62de342d9bdca806f3f1ea56486919a00497a18d457949c82bf8bfacc4423fc332074ddf71a49a8fe628fff.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_67f99bef3678c549a14b5f2ff790cce6aba338dca29020755444231b45fa0f980f795e3658496ba70739a099b47b22bc2eab564343ac6132309de3adbbae3455.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_09eecfdd96206ed13830b4b93cfb2cc75cd38083671a34194437b5734b5bb38712209dc335b07e3266ceb3c3a44a155b9bbe5f3e0e1105b19dd45d3def76f020.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_4c089fbdb88e3b624a6f884d3ba1bf606f003bfcd3742376d0d353cd62181dc663aa3811a56361c3100de488fc4d6595a50de2b26f058921ba74f5f2c1b5be00.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_897ff6ac314c5f5e0f496c6af624bd9abf296a02cb5aeb850b9220b6dc3ce2fc4004cb02ed8b59d59d4b9c9d90f050d6eebc1d08ecaebab2f671f7d9367e6410.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_67d1e619e71d36ae00ddcf85ee18628bb4eb64fcb3d6119b463e75cb987013420a21136d19cd03e6634ccc01cfa9af4a357930e4cf6900953b7812efb4f249fb.js