Language
日本語
English

Caution

JavaScript is disabled in your browser.
This site uses JavaScript for features such as search.
For the best experience, please enable JavaScript before browsing this site.

Python Dictionary

  1. Home
  2. Python Dictionary
  3. def Decorator / @ Syntax

def Decorator / @ Syntax

A decorator is a mechanism that takes a function or class and returns a new function (or class) with added functionality. Writing @decorator_name immediately before a function definition applies the decorator at the time the function is defined. Always use functools.wraps() when writing your own decorators to preserve the original function's metadata.

Syntax

from functools import wraps

# Define a decorator
def my_decorator(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        # Pre-processing
        result = func(*args, **kwargs)
        # Post-processing
        return result
    return wrapper

# Apply the decorator
@my_decorator
def my_function():
    pass

# Decorator that accepts arguments
def decorator_with_args(arg1, arg2):
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            return func(*args, **kwargs)
        return wrapper
    return decorator

Syntax / Functions

Syntax / FunctionDescription
@decorator_nameWritten before a function definition to apply the decorator.
@wraps(func)Copies the metadata of the original func (such as __name__) to the wrapper.
*args, **kwargsA pattern used inside a decorator to accept all arguments of the wrapped function.
@deco1 @deco2Stacking decorators. They are applied from bottom to top (deco2 first, then deco1).

Sample Code

from functools import wraps
import time

# Decorator that measures execution time
def timer(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        start = time.perf_counter()
        result = func(*args, **kwargs)
        elapsed = time.perf_counter() - start
        print(f"[{func.__name__}] elapsed: {elapsed:.4f}s")
        return result
    return wrapper

@timer
def heavy_process(n):
    """Simulates a heavy computation"""
    return sum(range(n))

print(heavy_process(1000000))   # [heavy_process] elapsed: 0.XXXXs

# Decorator with arguments (retry on failure)
def retry(times=3):
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            for i in range(times):
                try:
                    return func(*args, **kwargs)
                except Exception as e:
                    print(f"Attempt {i+1}/{times} failed: {e}")
            raise RuntimeError(f"{func.__name__} failed after {times} attempts")
        return wrapper
    return decorator

@retry(times=3)
def unstable_api():
    import random
    if random.random() < 0.7:
        raise ConnectionError("Connection error")
    return "Success"

# Stacking decorators (applying multiple decorators)
def bold(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        return f"**{func(*args, **kwargs)}**"
    return wrapper

def upper(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        return func(*args, **kwargs).upper()
    return wrapper

@bold       # Applied second (outer)
@upper      # Applied first (inner)
def greet(name):
    return f"hello, {name}"

print(greet('world'))   # **HELLO, WORLD** (upper → bold order)

# Class-based decorator
class Memoize:
    def __init__(self, func):
        self.func  = func
        self.cache = {}
        wraps(func)(self)   # Copy metadata

    def __call__(self, *args):
        if args not in self.cache:
            self.cache[args] = self.func(*args)
        return self.cache[args]

@Memoize
def fib(n):
    if n < 2:
        return n
    return fib(n - 1) + fib(n - 2)

print(fib(30))  # 832040 (fast thanks to caching)

Notes

A decorator is syntactic sugar in Python. Writing @my_decorator is equivalent to func = my_decorator(func). When decorators are stacked, they are applied from the bottom up (innermost to outermost).

A decorator that accepts arguments requires three levels of nested functions, but the structure is straightforward once you understand it: the outer function receives the arguments, the middle function receives the target function, and the innermost wrapper performs the actual wrapping logic.

Decorators are ideal for implementing cross-cutting concerns such as logging, authentication checks, caching, and validation. They help avoid code duplication and support the DRY (Don't Repeat Yourself) principle.

If you find any errors or copyright issues, please .