Fundamentals 7 min read

Creating Parameterless Decorators in Python: Examples and Use Cases

This article explains how to create various parameter‑less decorators in Python, providing clear examples for logging, performance measurement, authentication checks, result caching, and log‑level control, along with complete code snippets and explanations of their behavior.

Test Development Learning Exchange
Test Development Learning Exchange
Test Development Learning Exchange
Creating Parameterless Decorators in Python: Examples and Use Cases

In Python, writing decorators without parameters is a common need. Decorators can enhance or modify a function's behavior and are often used for tasks such as logging, performance statistics, transaction management, and more.

1. Simple logging decorator – This example shows a decorator that records a function's call, its return value, and execution time.

import time

def log(func):
    def wrapper(*args, **kwargs):
        start_time = time.time()
        print(f"Calling function '{func.__name__}'")
        result = func(*args, **kwargs)
        end_time = time.time()
        print(f"Function '{func.__name__}' returned {result} in {end_time - start_time:.4f} seconds")
        return result
    return wrapper

@log
def add(a, b):
    return a + b

@log
def greet(name):
    return f"Hello, {name}!"

result_add = add(5, 3)
result_greet = greet("Alice")
print(result_add)  # 输出:8
print(result_greet)  # 输出:Hello, Alice!

The log decorator records the function call and its return value while also measuring execution time.

2. General performance statistics decorator – This decorator tracks how many times a function is called and the total time spent executing it.

import time

def performance_stats(func):
    call_count = 0
    total_time = 0.0
    def wrapper(*args, **kwargs):
        nonlocal call_count, total_time
        start_time = time.time()
        print(f"Calling function '{func.__name__}'")
        result = func(*args, **kwargs)
        end_time = time.time()
        total_time += end_time - start_time
        call_count += 1
        print(f"Function '{func.__name__}' returned {result} in {end_time - start_time:.4f} seconds")
        print(f"Total calls: {call_count}, Total time: {total_time:.4f} seconds")
        return result
    return wrapper

@performance_stats
def factorial(n):
    if n == 0:
        return 1
    else:
        return n * factorial(n - 1)

result = factorial(5)
print(result)  # 输出:120

The performance_stats decorator reports each call and aggregates total execution time.

3. Authentication decorator – This decorator checks whether a user is logged in before allowing the wrapped function to run.

users = {
    "alice": "password123",
    "bob": "secret456"
}

def login_required(func):
    def wrapper(username, password, *args, **kwargs):
        if username in users and users[username] == password:
            print(f"User '{username}' authenticated")
            return func(username, *args, **kwargs)
        else:
            print("Authentication failed")
            return None
    return wrapper

@login_required
def view_profile(username):
    return f"Profile of user '{username}'"

result = view_profile("alice", "password123")
print(result)  # 输出:Profile of user 'alice'
result = view_profile("bob", "wrongpass")
print(result)  # 输出:None

The login_required decorator validates credentials and proceeds only on successful authentication.

4. Cache decorator – This decorator caches function results to avoid redundant calculations.

cache = {}

def memoize(func):
    def wrapper(*args, **kwargs):
        key = str(args) + str(kwargs)
        if key not in cache:
            print(f"Computing {func.__name__}({args}, {kwargs})")
            result = func(*args, **kwargs)
            cache[key] = result
        else:
            print(f"Retrieving {func.__name__}({args}, {kwargs}) from cache")
        return cache[key]
    return wrapper

@memoize
def fibonacci(n):
    if n <= 1:
        return n
    else:
        return fibonacci(n - 1) + fibonacci(n - 2)

result = fibonacci(10)
print(result)  # 输出:55

The memoize decorator stores computed results, reducing repeated work.

5. Log level decorator – This decorator logs messages at a specified logging level.

import logging

def log_level(level):
    def decorator(func):
        def wrapper(*args, **kwargs):
            logging.log(level, f"Calling function '{func.__name__}'")
            result = func(*args, **kwargs)
            logging.log(level, f"Function '{func.__name__}' returned {result}")
            return result
        return wrapper
    return decorator

@log_level(logging.DEBUG)
def debug_function():
    return "Debug message"

@log_level(logging.INFO)
def info_function():
    return "Info message"

debug_result = debug_function()
info_result = info_function()
print(debug_result)  # 输出:Debug message
print(info_result)  # 输出:Info message

The log_level decorator logs function calls and results using the chosen logging severity.

6. Summary – The article presented six practical, parameter‑less decorators: a simple logging decorator, a performance statistics decorator, an authentication decorator, a caching decorator, and a log‑level decorator, each illustrated with complete, runnable Python code.

PerformancePythoncachingLoggingauthenticationdecorator
Test Development Learning Exchange
Written by

Test Development Learning Exchange

Test Development Learning Exchange

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.