Python by Structure: Return Value Transformations with Decorators

Published: (December 3, 2025 at 11:44 PM EST)
2 min read
Source: Dev.to

Source: Dev.to

The Problem: Repetitive Output Transformations

def get_greeting(name):
    return f"hello, {name}".upper()

def get_status():
    return "system online".upper()

def get_error_message(code):
    return f"error code: {code}".upper()

Using a Decorator to Transform Return Values

def uppercase_result(func):
    """Decorator to convert a function's string result to uppercase."""
    def wrapper(*args, **kwargs):
        result = func(*args, **kwargs)
        if isinstance(result, str):
            return result.upper()
        return result
    return wrapper

@uppercase_result
def get_greeting(name):
    """Returns a personalized greeting."""
    return f"hello, {name}"

@uppercase_result
def get_status():
    """Returns the system status."""
    return "system online"

@uppercase_result
def get_error_message(code):
    """Returns an error message."""
    return f"error code: {code}"

# Usage
print(get_greeting("Alice"))
print(get_status())
print(get_error_message(404))

Output

HELLO, ALICE
SYSTEM ONLINE
ERROR CODE: 404

Understanding Return Value Interception

The decorator works by:

  1. Calling the original function.
  2. Capturing its result.
  3. Checking if the result is a string.
  4. Applying .upper() only when appropriate.
  5. Returning the (possibly transformed) result.

Type‑Safe Transformations

The type check prevents errors when a decorated function returns a non‑string value:

@uppercase_result
def get_error_code():
    """Returns a number, which should not be affected."""
    return 404

print(get_error_code())  # Outputs: 404

When to Use Return‑Value Decorators

Use return‑value transformation decorators when you need to:

  • Apply consistent formatting to function outputs (uppercase, lowercase, title case)
  • Round or format numeric results consistently
  • Sanitize or escape output for security
  • Convert between data formats (dict to JSON, object to string)
  • Add metadata or wrap results in a standard structure

Example: Rounding Numeric Results

def round_result(decimals=2):
    """Decorator to round numeric results to specified decimals."""
    def decorator(func):
        def wrapper(*args, **kwargs):
            result = func(*args, **kwargs)
            if isinstance(result, (int, float)):
                return round(result, decimals)
            return result
        return wrapper
    return decorator

@round_result(decimals=2)
def calculate_average(numbers):
    """Calculates the average of a list of numbers."""
    return sum(numbers) / len(numbers)

print(calculate_average([1.234, 2.567, 3.891]))  # Outputs: 2.56

Keeping Functions Clean

By separating concerns, functions remain focused on their core logic while decorators handle presentation or formatting:

@uppercase_result
def get_greeting(name):
    return f"hello, {name}"

Changing the transformation only requires updating the decorator, not every individual function. This promotes cleaner, more maintainable code.

Back to Blog

Related posts

Read more »

What Happens When You Run Python Code?

Python is a popular programming language, but have you ever wondered what happens behind the scenes when you run a Python program on your computer? In this arti...