Decorators

A decorator is a function that takes another function and extends the behavior of the latter function without explicitly modifying it.

# Define the check_number decorator
def check_number(func):
    def wrapper_func(*args, **kwargs):
        val1, val2 = args
        try:
            float(val1), float(val2)
            return func(*args, **kwargs)
        except Exception as e:
            print("Not a number")
    return wrapper_func

# Decorating a function
@check_number
def sum(val1, val2):
    return val1 + val2

result = sum('a', 0)

# Equivalent to:
result = check_number(sum('a', 0))

Note

when creating user defined decorators, it is recommended to use the “wraps” decorator from the functools module

from functools import wraps


def check_number(f):
    @wraps(f)
    def wrapper(*args, **kwds):
        print(f'Calling decorated function: {f.__name__=}; {args=} {kwds=}')
        val = f(*args, **kwds)
        print(f'Result: {val=}')
        return val
    return wrapper

# Decorating a function
@check_number
def sum(val1, val2):
    return val1 + val2

result = sum(2, 3)


# Equivalent to:
result = check_number(sum(2, 3))

References