Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Python Decorators: Core Mechanics and Interview Patterns

Tech May 8 3

A Python decorator is a higher-order function that accepts a callable and returns a replacement callable, enabling the injection of pre- or post-processing logic without altering the original function body. Applications include logging, caching, access control, performance timing, and transaction management. Extracting such cross-cutting concerns into decorators significantly improves code reusability.

Nested Functions

A nested function is defined inside another function rather than merely referencing it. The inner function resolves names by searching its local scope and then enclosing scopes.

def create_adder(base):
    def add(offset):
        return base + offset
    return add

increment = create_adder(10)
print(increment(5))  # 15

Because add closes over base, the parameter from the outer scope remains accessible after create_adder returns. Replacing the outer variable with a callable and the inner variable with arguments yields a universal decorator pattern:

def enhanced(func):
    def proxy(*args, **kwargs):
        # cross-cutting logic
        return func(*args, **kwargs)
    return proxy

Preserving Function Metadata

A naive decorator replaces the original function with its inner wrapper, changing attributes such as __name__. To avoid this, use functools.wraps:

from functools import wraps

def trace(func):
    @wraps(func)
    def proxy(*args, **kwargs):
        print(f"Executing {func.__name__}")
        return func(*args, **kwargs)
    return proxy

@trace
def greet():
    print("Hello")

Calling greet() prints the execution message and retains the original name.

Parameterized Decoratros

When the decorator itself requires configuration, a third nesting level accepts the decorator arguments and returns the actual decorator:

from functools import wraps

def measure(unit):
    def decorator(func):
        @wraps(func)
        def proxy(*args, **kwargs):
            import time
            start = time.time()
            result = func(*args, **kwargs)
            elapsed = time.time() - start
            print(f"{func.__name__} finished in {elapsed:.4f} {unit}")
            return result
        return proxy
    return decorator

@measure(unit="seconds")
def compute():
    sum(range(10000))

Stacking Decorators

Multiple decorators are applied bottom-up. Consider:

def border(func):
    def outer_wrap(*args, **kwargs):
        print("border-start")
        func(*args, **kwargs)
        print("border-end")
    return outer_wrap

def label(func):
    def inner_wrap(*args, **kwargs):
        print(f"target: {func.__name__}")
        func(*args, **kwargs)
    return inner_wrap

@border
@label
def action():
    print("running")

action()

This is equivalent to action = border(label(action)). Execution proceeds from the outermost wrapper inward:

border-start
target: action
running
border-end

The innermost decorator executes its side effects closest to the original callable, while the outermost controls the first and last actions of the combined call.

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.