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