파이썬 데코레이터를 사용하여 함수를 강화하는 방법

Python 데코레이터는 함수와 메서드를 수정하거나 개선하는 강력하고 유연한 방법입니다. 데코레이터는 함수를 추가 기능으로 래핑하는 방법을 제공하여 실제 코드를 수정하지 않고도 동작을 확장할 수 있습니다. 이 문서에서는 데코레이터의 개념, 데코레이터를 만들고 사용하는 방법, 몇 가지 실제 예를 소개합니다.

데코레이터란?

데코레이터는 다른 함수를 가져와 명시적으로 수정하지 않고 동작을 확장하는 함수입니다. Python에서 데코레이터는 기존 함수나 메서드에 로깅, 액세스 제어 또는 성능 측정과 같은 기능을 추가하는 데 자주 사용됩니다. 데코레이터는 @decorator_name 구문을 사용하여 함수에 적용됩니다.

# Basic example of a decorator
def my_decorator(func):
    def wrapper():
        print("Something is happening before the function is called.")
        func()
        print("Something is happening after the function is called.")
    return wrapper

@my_decorator
def say_hello():
    print("Hello!")

say_hello()

장식가의 작업 방식

함수에 데코레이터를 적용하면 Python은 기본적으로 다음 단계를 수행합니다.

  1. 데코레이터 함수는 원래 함수를 인수로 호출됩니다.
  2. 데코레이터 함수는 원래 함수의 동작을 향상시키거나 수정하는 새로운 함수(종종 wrapper라고 함)를 정의합니다.
  3. 데코레이터 함수는 새로운 함수를 반환합니다.
  4. 데코레이트된 함수가 호출되면, 실제로는 데코레이터가 반환한 새 함수를 호출합니다.

간단한 데코레이터 만들기

함수의 실행 시간을 측정하는 간단한 데코레이터를 만들어 보겠습니다. 이는 성능 테스트와 최적화에 유용합니다.

import time

def timing_decorator(func):
    def wrapper(*args, **kwargs):
        start_time = time.time()
        result = func(*args, **kwargs)
        end_time = time.time()
        print(f"Execution time: {end_time - start_time} seconds")
        return result
    return wrapper

@timing_decorator
def slow_function():
    time.sleep(2)
    print("Function finished!")

slow_function()

인수와 함께 데코레이터 사용

때로는 데코레이터에 인수를 전달하고 싶을 수도 있습니다. 이를 위해 데코레이터 팩토리를 만들어야 합니다. 데코레이터를 반환하는 함수입니다. 다음은 사용자 지정 메시지를 지정하기 위해 인수를 취하는 데코레이터의 예입니다.

def custom_message_decorator(message):
    def decorator(func):
        def wrapper(*args, **kwargs):
            print(message)
            return func(*args, **kwargs)
        return wrapper
    return decorator

@custom_message_decorator("Starting the function...")
def greet(name):
    print(f"Hello, {name}!")

greet("Alice")

클래스의 메서드에 대한 데코레이터

데코레이터는 클래스 내부의 메서드와 함께 사용할 수도 있습니다. 일반적인 용도로는 메서드 호출 로깅, 액세스 제어, 결과 캐싱이 있습니다. 다음은 데코레이터를 사용하여 클래스에서 메서드 호출을 로깅하는 예입니다.

def log_method_call(method):
    def wrapper(self, *args, **kwargs):
        print(f"Calling {method.__name__} with arguments {args} and keyword arguments {kwargs}")
        return method(self, *args, **kwargs)
    return wrapper

class MyClass:
    @log_method_call
    def my_method(self, x, y):
        print(f"Result: {x + y}")

obj = MyClass()
obj.my_method(5, 7)

체이닝 데코레이터

여러 데코레이터를 단일 함수에 적용할 수 있습니다. 가장 안쪽의 데코레이터에서 가장 바깥쪽 데코레이터까지 적용됩니다. 이를 통해 서로 다른 기능을 함께 구성할 수 있습니다. 다음은 두 데코레이터를 체인으로 연결하는 예입니다.

def uppercase_decorator(func):
    def wrapper(*args, **kwargs):
        result = func(*args, **kwargs)
        return result.upper()
    return wrapper

def exclamation_decorator(func):
    def wrapper(*args, **kwargs):
        result = func(*args, **kwargs)
        return result + "!"
    return wrapper

@exclamation_decorator
@uppercase_decorator
def greet(name):
    return f"Hello, {name}"

print(greet("Alice"))

결론

데코레이터는 Python에서 함수와 메서드의 동작을 향상시키거나 수정할 수 있는 다재다능한 도구입니다. 데코레이터를 사용하면 함수의 핵심 로직을 변경하지 않고도 코드베이스 전반에 재사용 가능한 기능을 추가할 수 있습니다. 로깅, 타이밍 또는 출력 수정을 위해 데코레이터는 코드를 깔끔하고 유지 관리하기 쉽게 유지하는 데 도움이 됩니다. 데코레이터를 사용하여 더 능숙해지고 Python 프로젝트에서 데코레이터의 힘을 활용하세요.