3.8. Decorator with Arguments

3.8.1. Syntax

Decorator:
@decorator(a, b)
def function(*args, **kwargs):
    pass
Is equivalent to:
decorator = decorator(a, b)(function)

3.8.2. Definition

def decorator(a=1, b=2):
    def function_wrapper(function):

        def args_wrapper(*args, **kwargs):
            return function(*args, **kwargs)
        return args_wrapper

    return function_wrapper

3.8.3. Usage

def decorator(a=1, b=2):
    def function_wrapper(function):

        def args_wrapper(*args, **kwargs):
            return function(*args, **kwargs)
        return args_wrapper

    return function_wrapper


@decorator(a=0)
def echo(name):
    print(name)


echo('Mark Watney')
# Mark Watney

3.8.4. Examples

3.8.4.1. Deprecated

def deprecated(removed_in_version=None):
    def decorator(fn):
        def write_message(*args, **kwargs):
            name = fn.__name__
            file = fn.__code__.co_filename
            line = fn.__code__.co_firstlineno + 1
            message = f"Call to deprecated function {name} in {file} at line {line}"
            message += f'\nIt will be removed in {removed_in_version}'

            import warnings
            warnings.warn(message, DeprecationWarning)
            return fn(*args, **kwargs)

        return write_message
    return decorator


@deprecated(removed_in_version=2.0)
def my_function():
    pass


my_function()
# /tmp/my_script.py:11: DeprecationWarning: Call to deprecated function my_function in /tmp/my_script.py at line 19
# It will be removed in 2.0

3.8.4.2. Timeout

Listing 467. Decorator usage
import signal
from time import sleep


def timeout(fn, seconds=2, error_message='Timeout'):

    def wrapper(*args, **kwargs):

        def handler(signum, frame):
            raise TimeoutError

        signal.signal(signal.SIGALRM, handler)
        signal.alarm(seconds)

        try:
            fn(*args, **kwargs)
        except TimeoutError:
            print(error_message)
        finally:
            signal.alarm(0)

    return wrapper


@timeout
def connect(username, password, host='127.0.0.1', port='80'):
    print('Connecting...')
    sleep(5)
    print('Connected')


connect('admin', 'admin')