데코레이터(Decorator)는 파이썬(Python)에서 함수나 메서드를 동적으로 수정하거나 확장할 수 있는 강력한 기능입니다. 데코레이터를 사용하면 코드의 중복을 줄이고, 깔끔하게 유지보수할 수 있으며, 로깅, 접근 제어, 성능 측정 등의 작업을 함수에 추가할 수 있습니다. 이번 포스팅에서는 파이썬 데코레이터의 개념과 사용법, 그리고 다양한 활용 사례를 살펴보겠습니다.

1. 데코레이터란?

데코레이터는 다른 함수를 감싸는(wrapper) 함수로, 원래 함수의 기능을 변경하거나 확장할 수 있는 함수입니다. 데코레이터는 보통 함수의 정의 위에 @데코레이터_이름과 같이 사용되며, 데코레이터 함수가 원래 함수를 인수로 받아 실행합니다.

1.1. 데코레이터의 기본 구조

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()

위 코드에서 my_decorator는 say_hello 함수를 감싸는 데코레이터입니다. say_hello 함수가 호출될 때마다, 데코레이터에 정의된 전후 코드가 함께 실행됩니다.

출력 결과는 다음과 같습니다:

Something is happening before the function is called.
Hello!
Something is happening after the function is called.

2. 데코레이터의 동작 방식

데코레이터는 함수를 인수로 받아서 새로운 함수를 반환합니다. 이 새로운 함수는 원래 함수의 동작을 확장하거나 수정할 수 있습니다. 데코레이터는 코드의 중복을 줄이고, 일관성을 유지하는 데 유용합니다.

2.1. 함수 데코레이터

함수 데코레이터는 함수의 동작을 수정하거나 추가적인 동작을 실행하는 데 사용됩니다.

def my_decorator(func):
    def wrapper():
        print("Function is being called")
        func()
        print("Function has finished")
    return wrapper

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

say_hello()

위 코드에서 say_hello 함수는 my_decorator 데코레이터로 감싸져서 호출될 때마다 추가적인 로그 메시지가 출력됩니다.

2.2. 인자가 있는 함수 데코레이터

데코레이터는 인자를 가진 함수도 감쌀 수 있습니다. 이를 위해 wrapper 함수에 *args와 **kwargs를 사용하여 모든 인수를 받아 처리할 수 있습니다.

def my_decorator(func):
    def wrapper(*args, **kwargs):
        print("Function is being called with arguments:", args, kwargs)
        return func(*args, **kwargs)
    return wrapper

@my_decorator
def greet(name, message="Hello"):
    print(f"{message}, {name}!")

greet("Alice")
greet("Bob", message="Hi")

출력 결과는 다음과 같습니다:

Function is being called with arguments: ('Alice',) {}
Hello, Alice!
Function is being called with arguments: ('Bob',) {'message': 'Hi'}
Hi, Bob!

3. 여러 데코레이터 사용하기

여러 데코레이터를 하나의 함수에 적용할 수 있습니다. 데코레이터는 아래에서 위로 적용됩니다.

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

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

print(greet("Alice"))

위 코드에서 greet 함수는 먼저 exclamation_decorator에 의해 감싸지고, 그 결과가 uppercase_decorator에 의해 처리됩니다.

출력 결과는 다음과 같습니다:

HELLO, ALICE!

4. 클래스 메서드 데코레이터

데코레이터는 클래스 메서드에도 적용할 수 있습니다. 이 경우 self나 cls와 같은 첫 번째 인수도 처리해야 합니다.

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

class MyClass:
    @method_decorator
    def hello(self, name):
        print(f"Hello, {name}!")

obj = MyClass()
obj.hello("Alice")

출력 결과는 다음과 같습니다:

Calling method hello with ('Alice',) and {}
Hello, Alice!

5. 파이썬 내장 데코레이터

파이썬은 몇 가지 내장 데코레이터를 제공합니다. 가장 많이 사용되는 내장 데코레이터는 @staticmethod, @classmethod, @property입니다.

5.1. @staticmethod

@staticmethod는 인스턴스나 클래스에 접근하지 않는 메서드를 정의할 때 사용됩니다.

class MyClass:
    @staticmethod
    def static_method():
        print("This is a static method.")

MyClass.static_method()  # 출력: This is a static method.

5.2. @classmethod

@classmethod는 클래스 자체에 접근하는 메서드를 정의할 때 사용됩니다.

class MyClass:
    count = 0

    @classmethod
    def increment(cls):
        cls.count += 1

MyClass.increment()
print(MyClass.count)  # 출력: 1

5.3. @property

@property는 클래스의 메서드를 속성처럼 사용할 수 있게 합니다.

class MyClass:
    def __init__(self, value):
        self._value = value

    @property
    def value(self):
        return self._value

    @value.setter
    def value(self, new_value):
        self._value = new_value

obj = MyClass(10)
print(obj.value)  # 출력: 10
obj.value = 20
print(obj.value)  # 출력: 20

6. 데코레이터의 실용적인 활용 사례

6.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"Function {func.__name__} took {end_time - start_time} seconds to execute.")
        return result
    return wrapper

@timer_decorator
def slow_function():
    time.sleep(2)
    print("Function complete.")

slow_function()

출력 결과는 다음과 같습니다:

Function complete.
Function slow_function took 2.0 seconds to execute.

6.2. 접근 제어

데코레이터를 사용하여 함수나 메서드에 대한 접근을 제어할 수 있습니다. 예를 들어, 사용자 인증이 필요한 기능을 데코레이터로 구현할 수 있습니다.

def require_authentication(func):
    def wrapper(user, *args, **kwargs):
        if not user.is_authenticated:
            print("User is not authenticated.")
            return
        return func(user, *args, **kwargs)
    return wrapper

class User:
    def __init__(self, name, is_authenticated):
        self.name = name
        self.is_authenticated = is_authenticated

@require_authentication
def view_dashboard(user):
    print(f"Welcome to your dashboard, {user.name}!")

user1 = User("Alice", True)
user2 = User("Bob", False)

view_dashboard(user1)  # 출력: Welcome to your dashboard, Alice!
view_dashboard(user2)  # 출력: User is not authenticated.

결론

이번 포스팅에서는 파이썬의 데코레이터에 대해 알아보았습니다. 데코레이터는 함수나 메서드의 동작을 동적으로 수정하거나 확장할 수 있는 강력한 기능으로, 코드의 중복을 줄이고, 유지보수를 쉽게 할 수 있습니다. 데코레이터의 기본 사용법부터 여러 데코레이터의 적용, 클래스 메서드에 대한 적용까지 다양한 예제를 통해 실습해 보면서 데코레이터의 강력한 기능을 경험해 보세요.


이 글을 통해 파이썬의 데코레이터를 이해하고, 실습을 통해 이를 사용하는 방법을 익힐 수 있을 것입니다. 데코레이터를 활용해 더 효율적이고 관리하기 쉬운

파이썬 코드를 작성해 보세요!

+ Recent posts