Fundamentals 7 min read

Understanding Python Decorators: Concepts, Examples, and Execution Order

This article explains Python decorators by first introducing the concept of closures, then demonstrating basic and advanced decorator implementations—including logging, timing, class-based decorators, and the use of functools.wraps—while also covering decorator execution order and providing annotated code examples.

Python Programming Learning Circle
Python Programming Learning Circle
Python Programming Learning Circle
Understanding Python Decorators: Concepts, Examples, and Execution Order

In Python, adding new functionality to an object can be done by directly extending its class, using composition, or employing inheritance; composition is generally preferred, while decorators represent a fourth, dynamic approach that modifies objects at runtime.

Typical decorator scenarios include logging, performance testing, transaction handling, and permission verification.

Understanding decorators requires grasping closures: a nested function that accesses variables from its enclosing scope and is returned as a callable. Decorators are essentially closures that receive a function as an argument.

Simple closure example:

def add_num(x):
    def sum_num(y):
        return x + y
    return sum_num

add_num5 = add_num(5)
total_num = add_num5(100)
print(total_num)

Basic timing decorator example:

def times_use(func):
    def count_times(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        end = time.time()
        print(end - start)
        return result
    return count_times

@times_use
def test_decorator():
    time.sleep(2)
    print("Test Decorator")

test_decorator()

Class‑based decorator that optionally logs execution time:

class logTime:
    def __init__(self, use_log=False):
        self._use_log = use_log
    def __call__(self, func):
        def _log(*args, **kwargs):
            start_time = time.time()
            result = func(*args, **kwargs)
            print(result)
            end_time = time.time()
            if self._use_log:
                print(end_time - start_time)
            return result
        return _log

@logTime(True)
def test_decorator():
    time.sleep(2)
    print("Test Decorator")
    return "Success"

test_decorator()

When a decorator needs to preserve the original function’s metadata (__name__, __doc__, etc.), functools.wraps should be applied:

from functools import wraps

def use_logging(level):
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            if level == "warn":
                logging.warn("%s is running" % func.__name__)
            result = func(*args, **kwargs)
            print(result)
            return result
        return wrapper
    return decorator

@use_logging("warn")
def test_decorator():
    """Test Decorator DocString"""
    time.sleep(2)
    print("Test Decorator")
    return "Success"

print(test_decorator.__name__)
print(test_decorator.__doc__)

Multiple decorators are executed in two phases: during function definition they are applied from the innermost to the outermost (inner‑to‑outer), while during function call they run from outermost to innermost (outer‑to‑inner). Example:

def decorator_a(func):
    print("Get in Decorator_a")
    def inner_a(*args, **kwargs):
        print("Get in Inner_a")
        return func(*args, **kwargs)
    return inner_a

def decorator_b(func):
    print("Get in Decorator_b")
    def inner_b(*args, **kwargs):
        print("Get in Inner_b")
        return func(*args, **kwargs)
    return inner_b

@decorator_b
@decorator_a
def test_decorator():
    """test decorator DocString"""
    print("Test Decorator")
    return "Success"

test_decorator()

Running the above yields:

Get in Decorator_a
Get in Decorator_b
Get in Inner_b
Get in Inner_a
Test Decorator

The output demonstrates that decorators are applied inside‑out at definition time and executed outside‑in at call time, allowing layered functionality without modifying the original function.

performancePythonloggingdecoratorClosurefunctionfunctools
Python Programming Learning Circle
Written by

Python Programming Learning Circle

A global community of Chinese Python developers offering technical articles, columns, original video tutorials, and problem sets. Topics include web full‑stack development, web scraping, data analysis, natural language processing, image processing, machine learning, automated testing, DevOps automation, and big data.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.