본문으로 건너뛰기
Previous
Next
Python Decorators | @decorator Syntax· functools.wraps

Python Decorators | @decorator Syntax· functools.wraps

Python Decorators | @decorator Syntax· functools.wraps

이 글의 핵심

Master Python decorators: function decorators, parameterized factories, logging, caching, auth, class decorators, and functools.wraps—with clear examples.

Introduction

“Dressing up functions”

Decorators are a powerful Python feature for adding behavior around functions (or classes).

1. Function decorators basics

A simple function decorator

def timer(func):
    """Measure how long a function runs."""
    import time
    
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        end = time.time()
        print(f"{func.__name__} took {end - start:.4f}s")
        return result
    
    return wrapper
@timer
def slow_function():
    import time
    time.sleep(1)
    return "done"
result = slow_function()
# slow_function took: 1.0012s

Logging decorator

def logger(func):
    """Log function calls."""
    def wrapper(*args, **kwargs):
        print(f"[call] {func.__name__}({args}, {kwargs})")
        result = func(*args, **kwargs)
        print(f"[return] {result}")
        return result
    return wrapper
@logger
def add(a, b):
    return a + b
add(3, 5)
# [call] add((3, 5), {})
# [return] 8

2. Decorators with arguments

Decorator factory

def repeat(times):
    """Run the wrapped function multiple times."""
    def decorator(func):
        def wrapper(*args, **kwargs):
            results = []
            for _ in range(times):
                result = func(*args, **kwargs)
                results.append(result)
            return results
        return wrapper
    return decorator
@repeat(3)
def greet(name):
    return f"Hello, {name}!"
print(greet("Alice"))
# ['Hello, Alice!', 'Hello, Alice!', 'Hello, Alice!']

3. Practical decorators

Memoization (caching)

def memoize(func):
    """Cache function results."""
    cache = {}
    
    def wrapper(*args):
        if args not in cache:
            cache[args] = func(*args)
        return cache[args]
    
    return wrapper
@memoize
def fibonacci(n):
    if n < 2:
        return n
    return fibonacci(n-1) + fibonacci(n-2)
print(fibonacci(100))  # very fast!

Authentication decorator

def require_auth(func):
    """Require an authenticated user."""
    def wrapper(user, *args, **kwargs):
        if not user.get('is_authenticated'):
            raise PermissionError("Login required")
        return func(user, *args, **kwargs)
    return wrapper
@require_auth
def delete_post(user, post_id):
    return f"Post {post_id} deleted"
# Usage
user = {'name': 'Alice', 'is_authenticated': True}
print(delete_post(user, 123))  # Post 123 deleted
guest = {'name': 'guest', 'is_authenticated': False}
# delete_post(guest, 123)  # PermissionError!

4. Class decorators

def singleton(cls):
    """Singleton pattern."""
    instances = {}
    
    def get_instance(*args, **kwargs):
        if cls not in instances:
            instances[cls] = cls(*args, **kwargs)
        return instances[cls]
    
    return get_instance
@singleton
class Database:
    def __init__(self):
        print("Database connection")
        self.connection = "Connected"
# Usage
db1 = Database()  # Database connection
db2 = Database()  # no extra print (same instance)
print(db1 is db2)  # True

5. functools.wraps

Preserve metadata

from functools import wraps
def my_decorator(func):
    @wraps(func)  # keep original function metadata
    def wrapper(*args, **kwargs):
        """Wrapper docstring."""
        return func(*args, **kwargs)
    return wrapper
@my_decorator
def greet(name):
    """Greeting function."""
    return f"Hello, {name}!"
print(greet.__name__)  # greet (without wraps you'd see wrapper)
print(greet.__doc__)   # Greeting function.

6. Real-world example: API retry decorator

import time
from functools import wraps
def retry(max_attempts=3, delay=1):
    """Retry on failure."""
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            for attempt in range(max_attempts):
                try:
                    return func(*args, **kwargs)
                except Exception as e:
                    if attempt == max_attempts - 1:
                        raise
                    print(f"Attempt {attempt + 1} failed: {e}")
                    time.sleep(delay)
        return wrapper
    return decorator
@retry(max_attempts=3, delay=0.5)
def fetch_data(url):
    import random
    if random.random() < 0.7:
        raise ConnectionError("connection failed")
    return f"data from {url}"

Practical tips

Decorator patterns

# ✅ Stacking multiple decorators
@timer
@logger
@retry(3)
def important_function():
    pass
# Execution order: retry → logger → timer → underlying function
# ✅ Always prefer functools.wraps
from functools import wraps
def my_decorator(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        return func(*args, **kwargs)
    return wrapper

Summary

Key takeaways

  1. Decorators wrap functions to add behavior.
  2. Syntax: @decorator_name above def.
  3. Parameters: use a decorator factory that returns the real decorator.
  4. wraps: preserve __name__, __doc__, and the function module.
  5. Uses: logging, caching, authentication, retries, timing.

Next steps


  • [Python functions | Parameters, return values, lambdas, decorators](/en/blog/python-series-04-functions/
  • [Python environment setup | Install Python on Windows and Mac](/en/blog/python-series-01-environment-setup/

자주 묻는 질문 (FAQ)

Q. 이 내용을 실무에서 언제 쓰나요?

A. Master Python decorators: function decorators, parameterized factories, logging, caching, auth, class decorators, and fu… 실무에서는 위 본문의 예제와 선택 가이드를 참고해 적용하면 됩니다.

Q. 선행으로 읽으면 좋은 글은?

A. 각 글 하단의 이전 글 또는 관련 글 링크를 따라가면 순서대로 배울 수 있습니다. Python 시리즈 목차에서 전체 흐름을 확인할 수 있습니다.

Q. 더 깊이 공부하려면?

A. cppreference와 해당 라이브러리 공식 문서를 참고하세요. 글 말미의 참고 자료 링크도 활용하면 좋습니다.


같이 보면 좋은 글 (내부 링크)

이 주제와 연결되는 다른 글입니다.

  • [Python Functions | Parameters· Return Values](/en/blog/python-series-04-functions/
  • [Python Classes | Object-Oriented Programming (OOP) Explained](/en/blog/python-series-05-classes/
  • [TypeScript Decorators](/en/blog/typescript-series-06-decorators/
  • [JavaScript Classes | ES6 Class Syntax Explained](/en/blog/javascript-series-07-classes/

이 글에서 다루는 키워드 (관련 검색어)

Python, Decorator, functools, Higher-Order Functions, Metaprogramming 등으로 검색하시면 이 글이 도움이 됩니다.