0Pricing
Python Academy · 강의

사용자 정의 데코레이터 작성

래퍼 함수와 functools.wraps를 사용해 데코레이터를 만듭니다.

사용자 정의 데코레이터 작성은(는) CoddyKit의 무료 Python Academy 강의입니다. 이것은 4개 중 2번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Python Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Python Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

소개

데코레이터는 다른 함수를 감싸 원본을 수정하지 않고 전후에 동작을 추가하는 함수입니다.

데코레이터란 무엇입니까?

함수 위의 @decorator는 다음 구문의 문법적 축약입니다: func = decorator(func). 데코레이터는 함수를 받아 wrapper를 반환합니다.
def shout(func):
    def wrapper(*a, **kw):
        result = func(*a, **kw)
        return str(result).upper()
    return wrapper
@shout
def greet(name): return f'hello {name}'
print(greet('Alice'))

래퍼 패턴

래퍼 함수는 원본 함수와 동일한 시그니처를 가집니다. 래퍼 함수는 내부에서 원본 함수를 호출하면서 주변에 동작을 추가합니다.
def timer(func):
    import time
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        print(f'{func.__name__} took {time.time()-start:.4f}s')
        return result
    return wrapper
@timer
def slow(): import time; time.sleep(0.01)
slow()

functools.wraps

래퍼에 @wraps(func)를 적용하면 원본 함수의 __name__, __doc__, __annotations__가 보존됩니다.
from functools import wraps
def log(func):
    @wraps(func)
    def wrapper(*a, **kw):
        print(f'calling {func.__name__}')
        return func(*a, **kw)
    return wrapper
@log
def add(a, b): return a + b
print(add.__name__)
add(1, 2)

인수를 받는 데코레이터

인수를 받는 데코레이터에는 한 단계 더 래핑이 필요합니다. 인수를 받아 데코레이터를 반환하는 팩토리 함수가 필요합니다.
def repeat(n):
    def decorator(func):
        from functools import wraps
        @wraps(func)
        def wrapper(*a, **kw):
            for _ in range(n): func(*a, **kw)
        return wrapper
    return decorator
@repeat(3)
def hi(): print('hi')
hi()

데코레이터 쌓기

여러 데코레이터는 아래에서 위로 쌓입니다: @d2 @d1은 func = d2(d1(func))을 의미합니다. 가장 바깥쪽 데코레이터(맨 위)는 마지막에 실행됩니다.
def bold(f):
    from functools import wraps
    @wraps(f)
    def w(*a,**k): return '<b>' + f(*a,**k) + '</b>'
    return w
def italic(f):
    from functools import wraps
    @wraps(f)
    def w(*a,**k): return '<i>' + f(*a,**k) + '</i>'
    return w
@bold
@italic
def text(): return 'hello'
print(text())

클래스 기반 데코레이터

__call__이 있는 클래스는 데코레이터가 될 수 있습니다. 호출 사이의 상태를 저장할 수 있습니다.
class Counter:
    def __init__(self, func): self.func,self.count=func,0
    def __call__(self, *a, **kw):
        self.count+=1
        return self.func(*a, **kw)
@Counter
def greet(name): return f'hi {name}'
greet('Alice'); greet('Bob')
print(greet.count)

메모이제이션 데코레이터

다시 계산하지 않도록 이전 결과를 캐시에 저장하십시오: if args in cache: return cache[args]. functools.lru_cache가 이 작업을 내장 기능으로 제공합니다.
from functools import lru_cache
@lru_cache(maxsize=None)
def fib(n):
    if n < 2: return n
    return fib(n-1) + fib(n-2)
print(fib(30))

권한 부여 데코레이터

데코레이터는 접근 제어에 자주 사용됩니다. 함수를 실행하기 전에 사용자가 로그인했는지 확인할 수 있습니다.
def requires_auth(func):
    from functools import wraps
    @wraps(func)
    def wrapper(user, *a, **kw):
        if not user.get('authenticated'):
            raise PermissionError('Not authenticated')
        return func(user, *a, **kw)
    return wrapper
@requires_auth
def dashboard(user): return 'Welcome!'
try: dashboard({'authenticated': False})
except PermissionError as e: print(e)

재시도 데코레이터

실패할 때 재시도하도록 함수를 감쌀 수 있습니다: for _ in range(retries): try: return func() except Exception: pass
import random
from functools import wraps
def retry(times=3):
    def dec(func):
        @wraps(func)
        def wrapper(*a, **kw):
            for i in range(times):
                try: return func(*a, **kw)
                except Exception as e:
                    if i==times-1: raise
        return wrapper
    return dec
@retry(3)
def flaky():
    if random.random()<0.7: raise ValueError
    return 'ok'
try: print(flaky())
except ValueError: print('failed')

데코레이터 모범 사례

항상 @functools.wraps를 사용하십시오. 데코레이터의 역할은 하나로 유지하십시오. 추가하는 동작을 문서화하십시오. 데코레이터를 데코레이션된 함수와 분리하여 테스트하십시오.
from functools import wraps
def validate_positive(func):
    @wraps(func)
    def wrapper(x, *a, **kw):
        if x <= 0: raise ValueError(f'{x} must be positive')
        return func(x, *a, **kw)
    return wrapper
@validate_positive
def sqrt(x): return x**0.5
print(sqrt(9))

빠른 확인

래퍼에 @functools.wraps(func)를 적용하면 어떤 일이 일어납니까?

복습

데코레이터: func = decorator(func)입니다. wrapper(*args, **kwargs)를 사용하십시오. @wraps는 메타데이터를 보존합니다. 매개변수가 있는 데코레이터에는 한 단계가 더 추가됩니다. 여러 @decorators를 사용해 쌓을 수 있습니다.

계속하기

훌륭하게 진행하고 계십니다! 다음 개념을 완전히 익힐 때까지 계속 학습하십시오.

자주 묻는 질문

“사용자 정의 데코레이터 작성” 강의는 무료인가요?

네 — “사용자 정의 데코레이터 작성” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Python Academy 강의 전체를 잠금 해제할 수 있습니다. Python Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

“사용자 정의 데코레이터 작성”에서 뭘 배우나요?

래퍼 함수와 functools.wraps를 사용해 데코레이터를 만듭니다. 브라우저에서 직접 실행하는 실습 코드로 Python Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

Python Academy을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 Python Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 2번째 강의입니다.

“사용자 정의 데코레이터 작성” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 Python Academy 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 Python Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. 일급 객체로서의 함수
  2. 사용자 정의 데코레이터 작성
  3. @property 데코레이터
  4. @classmethod와 @staticmethod
← Python Academy(으)로 돌아가기