python 에서 데코레이터

연결 문서

python 에서 데코레이터

데코레이터란 무엇인가?

데코레이터는 함수에 새로운 기능을 추가하는 도구임. 마치 선물을 포장지로 감싸는 것처럼, 함수에 데코레이터를 적용하면 그 함수에 부가적인 기능을 덧붙일 수 있음.

왜 데코레이터를 사용할까?

  • 코드 재사용성 증가: 반복되는 코드를 줄일 수 있음.
  • 코드 가독성 향상: 핵심 기능과 부가 기능을 분리하여 코드가 깔끔해짐.
  • 유지 보수 용이: 한 곳에서 부가 기능을 관리할 수 있어 수정이 쉬워짐.

데코레이터를 현실에 비유하기 : 카페에서 주문하기

데코레이터를 이해하기 어려울 수 있으니, 현실적인 예로 비유해보겠음.

  • 당신이 커피를 주문한다고 가정해보겠음.
  • 기본적으로 커피는 에스프레소 샷으로 만들어짐.
  • 여기에 시럽 추가휘핑크림 추가 등의 옵션을 더할 수 있음.

여기서 에스프레소는 기본 함수이고, 시럽 추가휘핑크림 추가는 데코레이터와 같음.

간단한 예제로 이해하기

예제 1 : 카페에서 주문하기

기본 함수 만들기

def 커피():
    return "에스프레소"

커피() 함수를 호출하면 “에스프레소”를 반환함.

시럽 추가 데코레이터 만들기

def 시럽_추가(함수):
    def wrapper():
        결과 = 함수()
        return 결과 + " + 시럽"
    return wrapper

시럽_추가 데코레이터는 커피에 시럽을 추가함.

휘핑크림 추가 데코레이터 만들기

def 휘핑크림_추가(함수):
    def wrapper():
        결과 = 함수()
        return 결과 + " + 휘핑크림"
    return wrapper

휘핑크림_추가 데코레이터는 커피에 휘핑크림을 추가함.

데코레이터 적용하기

@시럽_추가
def 커피():
    return "에스프레소"

이렇게 하면 커피() 함수를 호출할 때 시럽이 추가됨.

결과 확인하기

주문 = 커피()
print(주문)

출력:

에스프레소 + 시럽

여러 데코레이터 적용하기

데코레이터는 여러 개를 적용할 수 있음.

@휘핑크림_추가
@시럽_추가
def 커피():
    return "에스프레소"

이렇게 하면 커피() 함수에 시럽과 휘핑크림이 모두 추가됨.

결과 확인하기

주문 = 커피()
print(주문)

출력:

에스프레소 + 시럽 + 휘핑크림

예제 2 : 간단한 인사하기

기본 함수 만들기

def 인사():
    print("안녕하세요!")

인사() 함수를 호출하면 “안녕하세요!”가 출력됨.

함수에 부가 기능 추가하기 (데코레이터 없이)

함수가 호출될 때마다 로그를 출력하고 싶음.

def 인사():
    print("인사 함수가 호출되었음")
    print("안녕하세요!")

하지만 이런 방식은 함수마다 코드를 추가해야 해서 비효율적임.

데코레이터 만들기

def 로그_데코레이터(함수):
    def wrapper():
        print(f"{함수.__name__} 함수가 호출되었음")
        함수()
    return wrapper

로그_데코레이터는 함수 호출 전에 로그를 출력해주는 데코레이터임.

데코레이터 적용하기

@로그_데코레이터
def 인사():
    print("안녕하세요!")

@로그_데코레이터를 사용하여 인사 함수에 로그 기능을 추가했음.

결과 확인하기

인사()

출력:

인사 함수가 호출되었음
안녕하세요!

함수 내부 코드를 수정하지 않고도 로그 기능을 추가했음.

조금 더 복잡한 예제 : 실행 시간 측정

실행 시간 측정 데코레이터 만들기

import time

def 실행시간_데코레이터(함수):
    def wrapper():
        시작시간 = time.time()
        함수()
        종료시간 = time.time()
        print(f"실행 시간: {종료시간 - 시작시간}")
    return wrapper

데코레이터 적용하기

@실행시간_데코레이터
def 느린_함수():
    time.sleep(2)
    print("작업 완료!")

결과 확인하기

느린_함수()

출력:

작업 완료!
실행 시간: 2.002초

함수의 실행 시간을 자동으로 측정해줌.

또 다른 예제: 로그인 확인 데코레이터

웹 애플리케이션에서 사용자 로그인 여부를 확인하는 기능을 데코레이터로 만들어보겠음.

로그인 확인 데코레이터 만들기

def 로그인_확인(함수):
    def wrapper(user):
        if not user['로그인']:
            print("로그인이 필요합니다.")
            return
        return 함수(user)
    return wrapper

데코레이터 적용하기

@로그인_확인
def 프로필_보기(user):
    print(f"{user['이름']}님의 프로필입니다.")

사용자 데이터 예시

사용자1 = {'이름': '철수', '로그인': True}
사용자2 = {'이름': '영희', '로그인': False}

결과 확인하기

프로필_보기(사용자1)
# 출력: 철수님의 프로필입니다.

프로필_보기(사용자2)
# 출력: 로그인이 필요합니다.

프로필_보기 함수를 호출할 때 로그인 여부를 자동으로 확인함.

데코레이터의 동작 원리 이해하기

데코레이터는 함수를 입력으로 받아 또 다른 함수를 반환하는 함수임.

데코레이터 함수 구조

def 데코레이터(함수):
    def wrapper():
        # 부가 기능 추가
        결과 = 함수()
        # 부가 기능 추가
        return 결과
    return wrapper
  • 데코레이터 함수는 함수를 입력으로 받음.
  • wrapper 함수 안에서 원본 함수를 호출하고 결과를 반환함.
  • 데코레이터 함수는 wrapper 함수를 반환함.

데코레이터 적용 과정

@데코레이터
def 원본_함수():
    pass

이 코드는 다음과 동일함.

def 원본_함수():
    pass

원본_함수 = 데코레이터(원본_함수)

즉, 원본 함수가 데코레이터 함수에 의해 감싸여서 새로운 함수로 대체됨.

여러 인자를 가진 함수에 데코레이터 적용하기

인자를 가진 함수에도 데코레이터를 적용하려면 *args**kwargs를 사용하면 됨.

데코레이터 수정하기

def 로그_데코레이터(함수):
    def wrapper(*args, **kwargs):
        print(f"{함수.__name__} 함수가 호출되었음")
        return 함수(*args, **kwargs)
    return wrapper

인자를 가진 함수에 적용하기

@로그_데코레이터
def 덧셈(a, b):
    return a + b

결과 = 덧셈(3, 5)
print(f"결과: {결과}")

출력:

덧셈 함수가 호출되었음
결과: 8

정리하며

  • 데코레이터는 함수에 부가적인 기능을 쉽게 추가할 수 있게 해주는 도구임.
  • @데코레이터_이름을 사용하여 간단하게 적용할 수 있음.
  • 부가 기능을 별도의 함수로 분리하여 코드의 재사용성과 가독성을 높일 수 있음.

마치며

처음에는 데코레이터가 어려워 보일 수 있지만, 예제를 따라 해보면서 이해하면 큰 도움이 될 것임. 직접 다양한 데코레이터를 만들어보고 적용해보면서 파이썬의 강력한 기능을 활용해보길 바람.




    Enjoy Reading This Article?

    Here are some more articles you might like to read next:

  • 옵시디언에서 일정 관리
  • LangChain Expression Language(LCEL)
  • 우도(likelihood)
  • 특정 커밋으로 돌아가는 방법
  • Git과 GitHub는 뭐가 다를까( 초보자를 위한 쉬운 설명)