Python의 필수 데코레이터 심층 분석

Python 데코레이터 핵심 요약

데코레이터기능 개요
@classmethod클래스 메서드 정의, 첫 인자로 클래스 객체(cls) 전달
@staticmethod인스턴스/클래스 독립적인 유틸리티 메서드 정의
@property메서드를 속성처럼 접근하도록 변환
@dataclass데이터 클래스용 메서드 자동 생성
@lru_cache함수 결과 LRU 캐싱
@cache무제한 캐싱 (Python 3.9+)
@cached_property초기 접근시 계산된 속성 캐싱
@wraps데코레이터에서 원본 함수 메타데이터 보존
@overload정적 타입 힌트를 위한 다중 함수 시그니처
@singledispatch인자 타입 기반 함수 분기 처리
@contextmanager컨텍스트 관리자 간결 구현
@final클래스/메서드 상속/재정의 방지

1. @classmethod - 클래스 메서드

클래스 자체를 첫 번째 인자(cls)로 받는 메서드 정의

class Employee:
    company = "TechCorp"
    
    def __init__(self, id, name):
        self.id = id
        self.name = name
    
    @classmethod
    def from_record(cls, record):
        """레코드 문자열에서 객체 생성"""
        emp_id, emp_name = record.split(':')
        return cls(int(emp_id), emp_name)
    
    @classmethod
    def get_company(cls):
        return cls.company

emp = Employee.from_record("101:Alice")
print(emp.name)  # Alice
print(Employee.get_company())  # TechCorp

2. @staticmethod - 정적 메서드

클래스/인스턴스 상태에 독립적인 유틸리티 함수

class MathOps:
    @staticmethod
    def multiply(a, b):
        return a * b
    
    @staticmethod
    def is_positive(num):
        return num > 0

print(MathOps.multiply(4, 5))  # 20
print(MathOps.is_positive(-3))  # False

3. @property - 속성 변환기

메서드를 getter/setter가 있는 속성으로 변환

class Rectangle:
    def __init__(self, w, h):
        self._width = w
        self._height = h
    
    @property
    def width(self):
        return self._width
    
    @width.setter
    def width(self, val):
        if val <= 0:
            raise ValueError("너비는 0보다 커야 함")
        self._width = val
    
    @property
    def area(self):
        return self._width * self._height

rect = Rectangle(4, 5)
print(rect.area)  # 20
rect.width = 6  # setter 호출

4. @dataclass - 데이터 클래스

데이터 보관 클래스용 메서드 자동 생성

from dataclasses import dataclass

@dataclass
class Product:
    item_id: str
    price: float
    in_stock: bool = True

prod = Product("P1001", 29.99)
print(prod)  # Product(item_id='P1001', price=29.99, in_stock=True)

5. @lru_cache - LRU 캐싱

함수 결과를 LRU 알고리즘으로 캐싱

from functools import lru_cache

@lru_cache(maxsize=100)
def fib(n):
    if n < 2:
        return n
    return fib(n-1) + fib(n-2)

print(fib(30))  # 빠른 계산

6. @cache - 무제한 캐싱

결과를 무제한으로 캐싱 (Python 3.9+)

from functools import cache

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

print(factorial(10))  # 3628800

7. @cached_property - 캐싱 속성

초기 접근시 계산된 속성 값 캐싱

from functools import cached_property

class DataLoader:
    def __init__(self, source):
        self.source = source
    
    @cached_property
    def content(self):
        print("데이터 로드 중...")
        return open(self.source).read()

loader = DataLoader("data.txt")
print(loader.content)  # 첫 접근시 계산
print(loader.content)  # 캐시 사용

8. @wraps - 메타데이터 보존

데코레이터에서 원본 함수 정보 유지

from functools import wraps

def debug_deco(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        print(f"{func.__name__} 실행")
        return func(*args, **kwargs)
    return wrapper

@debug_deco
def sample():
    """테스트 함수"""
    pass

print(sample.__name__)  # sample
print(sample.__doc__)   # 테스트 함수

9. @overload - 다중 시그니처

정적 타입 힌트를 위한 함수 오버로딩

from typing import overload

@overload
def parse(input: str) -> str: ...
@overload
def parse(input: bytes) -> int: ...

def parse(input):
    if isinstance(input, str):
        return input.upper()
    elif isinstance(input, bytes):
        return len(input)

result = parse("text")  # 타입 힌트: str 반환

10. @singledispatch - 타입 분기

첫 번째 인자 타입에 따른 함수 분기

from functools import singledispatch

@singledispatch
def process(data):
    print("기본 처리")

@process.register(int)
def _(data):
    print("정수 처리:", data)

process(10)   # 정수 처리: 10
process("x")  # 기본 처리

11. @contextmanager - 컨텍스트 관리자

with 문 지원 리소스 관리자 생성

from contextlib import contextmanager

@contextmanager
def db_session(db_url):
    conn = connect(db_url)
    try:
        yield conn
        conn.commit()
    except:
        conn.rollback()
        raise
    finally:
        conn.close()

with db_session("db://localhost") as session:
    session.execute("UPDATE table SET status=1")

12. @final - 상속 제한

클래스/메서드 재정의 방지 (정적 검사용)

from typing import final

@final
class BaseAPI:
    @final
    def authenticate(self):
        pass

# 정적 검사기에서 오류 감지
class CustomAPI(BaseAPI):  # 오류: final 클래스 상속 불가
    def authenticate(self):  # 오류: final 메서드 재정의 불가
        pass

태그: python 데코레이터 classmethod staticmethod property

8월 7일 05:29에 게시됨