티스토리 뷰

목차




    Python Logo

    서론

    프로젝트를 하다 보면 코드를 줄이면서도 기능을 강화하는 방법을 찾게 됩니다. 특히 함수나 메서드에 기능을 더하고 싶을 때는 데코레이터가 아주 좋은 도구가 될 수 있어요. 처음엔 조금 낯설지만, 익숙해지면 반복 작업을 줄여주고 코드의 가독성도 높여줍니다. 제 경험상, 처음엔 단순한 예제로 데코레이터가 어떤 식으로 작동하는지 천천히 익혀가는 게 좋습니다. 이제, Python에서 데코레이터를 쉽게 시작해 봅시다.


    1. 데코레이터란 무엇인가?

    Python에서 **데코레이터(decorator)**는 함수를 감싸 추가적인 기능을 부여하는 도구입니다. 데코레이터를 사용하면 함수를 수정하지 않고도 기능을 확장할 수 있어서, 특히 중복 코드 줄이기에 유용합니다. 함수 위에 @데코레이터_이름 형태로 추가하여 데코레이터를 적용할 수 있습니다.

    1.1 기본적인 데코레이터 구조

    데코레이터는 보통 다른 함수를 매개변수로 받아서 내부에서 새 함수를 정의한 후, 이 새로운 함수를 반환합니다. 이렇게 하면 감싸진 함수가 실행되면서 데코레이터가 제공하는 추가 기능이 더해집니다.

    def decorator_function(original_function):
        def wrapper_function():
            print("데코레이터로 확장된 기능입니다.")
            return original_function()
        return wrapper_function

    1.2 데코레이터의 기본 사용법

    데코레이터를 함수에 적용하려면 함수 정의 바로 위에 @데코레이터_이름을 추가합니다. 이때 데코레이터가 먼저 실행되고, 그 후에 원래 함수가 실행됩니다.

    @decorator_function
    def say_hello():
        print("안녕하세요!")
    
    say_hello()
    # 출력:
    # 데코레이터로 확장된 기능입니다.
    # 안녕하세요!

    이제 say_hello 함수가 호출될 때마다 데코레이터로 확장된 기능입니다.라는 메시지가 함께 출력됩니다.


    2. 함수형 데코레이터 만들기

    2.1 데코레이터의 매개변수 전달

    데코레이터를 사용하다 보면 매개변수를 받아서 처리하는 함수에도 적용해야 할 때가 많습니다. 이를 위해 데코레이터 내부에서 *args**kwargs를 활용하여 어떤 매개변수라도 처리할 수 있도록 합니다.

    def decorator_function(original_function):
        def wrapper_function(*args, **kwargs):
            print("데코레이터 실행 중")
            return original_function(*args, **kwargs)
        return wrapper_function

    2.2 매개변수 있는 함수에 데코레이터 적용하기

    예를 들어, 아래는 인사말과 이름을 매개변수로 받아 출력하는 함수입니다. 이 함수에 데코레이터를 적용하여 확장된 기능을 추가해 보겠습니다.

    @decorator_function
    def greet(greeting, name):
        print(f"{greeting}, {name}님!")
    
    greet("안녕하세요", "철수")
    # 출력:
    # 데코레이터 실행 중
    # 안녕하세요, 철수님!

    greet 함수는 데코레이터가 매개변수를 처리하면서 확장된 기능을 더한 후 실행됩니다.


    3. 데코레이터의 다양한 활용 사례

    데코레이터는 단순히 출력 메시지를 추가하는 것 이상의 다양한 활용이 가능합니다. 다음은 데코레이터를 실무에서 활용할 수 있는 몇 가지 예시입니다.

    3.1 실행 시간 측정 데코레이터

    코드의 실행 시간을 확인하고 싶을 때, 직접 시간을 체크하는 코드를 반복 작성하는 대신, 데코레이터로 실행 시간 측정 기능을 구현할 수 있습니다.

    import time
    
    def timer_decorator(func):
        def wrapper(*args, **kwargs):
            start_time = time.time()
            result = func(*args, **kwargs)
            end_time = time.time()
            print(f"{func.__name__} 함수 실행 시간: {end_time - start_time} 초")
            return result
        return wrapper
    
    @timer_decorator
    def sample_task():
        time.sleep(2)
        print("작업 완료")
    
    sample_task()
    # 출력:
    # 작업 완료
    # sample_task 함수 실행 시간: 2.002 초

    3.2 접근 제어 데코레이터

    특정 조건을 만족하는 사용자만 함수를 사용할 수 있도록 제한하는 접근 제어를 데코레이터로 쉽게 구현할 수 있습니다.

    def access_control_decorator(func):
        def wrapper(user_role):
            if user_role == "admin":
                return func()
            else:
                print("접근 권한이 없습니다.")
        return wrapper
    
    @access_control_decorator
    def sensitive_task():
        print("민감한 작업을 수행 중입니다.")
    
    sensitive_task("admin")  # "민감한 작업을 수행 중입니다." 출력
    sensitive_task("guest")  # "접근 권한이 없습니다." 출력

    access_control_decoratoruser_role을 검사하여, 적절한 권한이 있을 때만 원래 함수를 실행합니다.

    3.3 로그 기록 데코레이터

    프로그램 실행 중 발생하는 중요한 작업들을 기록하기 위해 로그 데코레이터를 사용할 수 있습니다.

    def log_decorator(func):
        def wrapper(*args, **kwargs):
            print(f"{func.__name__} 함수가 실행되었습니다.")
            return func(*args, **kwargs)
        return wrapper
    
    @log_decorator
    def data_processing():
        print("데이터 처리 중")
    
    data_processing()
    # 출력:
    # data_processing 함수가 실행되었습니다.
    # 데이터 처리 중

    이처럼 log_decorator는 함수 호출 기록을 남길 때 매우 유용하게 사용할 수 있습니다.


    4. 클래스를 사용한 데코레이터

    Python에서는 클래스를 데코레이터로 사용할 수도 있습니다. 클래스 데코레이터는 주로 데코레이터가 상태를 유지해야 하는 경우에 유용합니다.

    4.1 기본 클래스 데코레이터 구조

    클래스 데코레이터는 __call__ 메서드를 정의하여 데코레이터처럼 작동하게 합니다. 함수 호출 시마다 __call__ 메서드가 실행됩니다.

    class ClassDecorator:
        def __init__(self, func):
            self.func = func
    
        def __call__(self, *args, **kwargs):
            print("클래스 데코레이터 실행")
            return self.func(*args, **kwargs)
    
    @ClassDecorator
    def display_message():
        print("메시지를 출력합니다.")
    
    display_message()
    # 출력:
    # 클래스 데코레이터 실행
    # 메시지를 출력합니다.

    4.2 클래스 데코레이터로 상태 관리하기

    예를 들어 함수가 몇 번 호출되었는지 추적하려면 클래스를 사용해 상태를 유지할 수 있습니다.

    class CallCounter:
        def __init__(self, func):
            self.func = func
            self.count = 0
    
        def __call__(self, *args, **kwargs):
            self.count += 1
            print(f"{self.func.__name__} 호출 횟수: {self.count}")
            return self.func(*args, **kwargs)
    
    @CallCounter
    def sample_function():
        print("샘플 함수 실행")
    
    sample_function()
    sample_function()
    # 출력:
    # sample_function 호출 횟수: 1
    # 샘플 함수 실행
    # sample_function 호출 횟수: 2
    # 샘플 함수 실행

    이 클래스 데코레이터는 호출 횟수를 카운팅하여 상태를 유지합니다. 함수가 호출될 때마다 카운팅되어 기록됩니다.


    5. 실습 예제 - 데코레이터를 직접 만들어 보기

    5.1 실행 시간과 결과 저장 데코레이터 만들기

    다음은 함수의 실행 시간과 결과를 저장하는 데코레이터를 작성해 보세요.

    import time
    
    class TimeLogger:
        def __init__(self, func):
            self.func = func
    
        def __call__(self, *args, **kwargs):
            start_time = time.time()
            result = self.func(*args, **kwargs)
            end_time = time.time()
            duration = end_time - start_time
            print(f"{self.func.__name__} 실행 시간: {duration:.2f} 초")
            return result
    
    @TimeLogger
    def complex_task():
        time.sleep(1)
        return "작업 결과"
    
    output = complex_task()
    print("결과:", output)

    5.2 사용자 입력 검증 데코레이터 작성하기

    아래 데코레이터는 사용자로부터 입력받은 값이 양수인지 확인하는 역할을 합니다. 입력이 양수가 아니면 경고 메시지를 출력합니다.

    def positive_input_validator(func):
        def wrapper(number):
            if number < 0:
                print("경고: 양수를
    
     입력해야 합니다.")
                return
            return func(number)
        return wrapper
    
    @positive_input_validator
    def display_number(number):
        print("입력된 숫자:", number)
    
    display_number(10)  # 정상 출력
    display_number(-5)  # 경고 출력

    요약

    데코레이터는 Python 코드의 가독성과 효율성을 크게 높이는 유용한 기능입니다. 데코레이터로 중복 작업을 줄이고, 클래스 데코레이터를 통해 상태를 관리하는 다양한 활용을 익혀보세요. 실무에서도 여러 번 사용하게 될 강력한 도구입니다.


    디스크립션: Python 데코레이터는 코드 재사용과 확장성을 높이는 필수 도구입니다. 함수형과 클래스형 데코레이터를 실습하며, 데코레이터 활용법을 초보자도 쉽게 익혀보세요.