파이썬의 데코레이터
이 문서는 파이썬의 데코레이터에 대해 설명합니다.
YouTube Video
파이썬의 데코레이터
파이썬 데코레이터는 함수나 메서드에 추가적인 기능을 더할 수 있는 강력한 기능입니다. 데코레이터를 사용하면 기존 코드를 수정하지 않고 새로운 기능을 추가할 수 있어, 코드 재사용성과 유지보수성을 향상시킬 수 있습니다.
데코레이터의 기초
파이썬 데코레이터는 함수를 인수로 받아 추가 기능이 있는 새 함수를 반환하는 방식으로 동작합니다. 데코레이터를 사용하면 함수에 전처리나 후처리를 간단히 추가할 수 있습니다.
데코레이터를 사용하지 않으면 함수의 동작을 변경하려면 함수 자체를 직접 수정해야 합니다. 데코레이터를 사용하면 원래 구현을 수정하지 않고도 기능을 확장할 수 있습니다.
데코레이터의 기본 구조
1def my_decorator(func):
2 def wrapper():
3 print("Before the function call")
4 func()
5 print("After the function call")
6 return wrapper
7
8@my_decorator
9def say_hello():
10 print("Hello!")
11
12say_hello()
이 예제에서 my_decorator
함수는 데코레이터 역할을 하여 say_hello
함수를 감쌉니다. @my_decorator
문법을 사용하여 데코레이터를 적용하며, say_hello()
가 호출되면 데코레이터에서 제공하는 전처리와 후처리가 자동으로 실행됩니다.
데코레이터 작동 방식
데코레이터는 다음 단계에서 작동합니다.
-
데코레이터는 함수(또는 메서드)를 인수로 받습니다.
-
원래 함수를 실행하기 위한 래퍼 함수를 정의합니다.
-
래퍼 함수는 원래 함수를 실행하기 전 또는 후에 추가 처리를 수행합니다.
-
데코레이터는 래퍼 함수를 반환합니다. 결과적으로 원래 함수는 새로 데코레이트된 함수로 대체됩니다.
인수를 가진 함수의 데코레이터
인수를 가진 함수에 데코레이터를 적용할 때 래퍼 함수는 해당 인수를 받을 수 있도록 조정되어야 합니다.
1def my_decorator(func):
2 def wrapper(*args, **kwargs):
3 print("Before the function call")
4 result = func(*args, **kwargs)
5 print("After the function call")
6 return result
7 return wrapper
8
9@my_decorator
10def greet(name):
11 print(f"Hello, {name}!")
12
13greet("Alice")
*args
와 **kwargs
를 사용하면 임의의 개수의 인수와 키워드 인수를 수용하는 함수를 처리할 수 있습니다. 이를 통해 데코레이터를 임의의 유형의 인수를 가진 함수에 일반적으로 적용할 수 있습니다.
데코레이터 적용 예시
로그 기록용 데코레이터
데코레이터는 종종 로그 기능을 추가하는 데 사용됩니다. 예를 들어, 함수 실행 전후를 로그로 기록하는 데코레이터를 작성함으로써 함수가 호출된 시점과 실행에 걸리는 시간을 기록할 수 있습니다.
1import time
2
3def log_time(func):
4 def wrapper(*args, **kwargs):
5 start_time = time.time()
6 print(f"Calling function '{func.__name__}'...")
7 result = func(*args, **kwargs)
8 end_time = time.time()
9 print(f"Function '{func.__name__}' completed in {end_time - start_time} seconds")
10 return result
11 return wrapper
12
13@log_time
14def long_task(duration):
15 time.sleep(duration)
16 print("Task completed!")
17
18long_task(2)
이 예에서는 log_time
데코레이터가 함수의 실행 시간을 측정하고 이를 로그로 출력합니다. long_task
함수는 데코레이터로 감싸져 있으며, 실행 시간은 런타임 동안 기록됩니다.
권한 관리를 위한 데코레이터
데코레이터는 권한 관리에도 사용할 수 있습니다. 예를 들어, 사용자가 특정 권한을 가지고 있는지 확인하여 처리를 제한할 수 있습니다.
1def requires_permission(user_role):
2 def decorator(func):
3 def wrapper(*args, **kwargs):
4 if user_role != "admin":
5 print("Permission denied!")
6 return
7 return func(*args, **kwargs)
8 return wrapper
9 return decorator
10
11@requires_permission("admin")
12def delete_user(user_id):
13 print(f"User {user_id} has been deleted.")
14
15delete_user(123) # Executed
16delete_user = requires_permission("guest")(delete_user)
17delete_user(456) # Permission denied!
requires_permission
데코레이터는 사용자의 역할에 따라 함수 실행을 제한합니다. 이러한 로직을 데코레이터에 통합함으로써 권한 관리 로직이 코드 전체에 분산되는 것을 방지하고 가독성을 높일 수 있습니다.
데코레이터 중첩
여러 데코레이터를 적용하는 것이 가능합니다. 여러 데코레이터가 단일 함수에 적용되었을 경우, 위에서 아래 순서대로 실행됩니다.
1def uppercase(func):
2 def wrapper(*args, **kwargs):
3 result = func(*args, **kwargs)
4 return result.upper()
5 return wrapper
6
7def exclaim(func):
8 def wrapper(*args, **kwargs):
9 result = func(*args, **kwargs)
10 return result + "!"
11 return wrapper
12
13@uppercase
14@exclaim
15def greet(name):
16 return f"Hello, {name}"
17
18print(greet("Alice")) # "HELLO, ALICE!"
이 예제에서는 두 개의 데코레이터가 greet
함수에 적용됩니다. @exclaim
데코레이터는 문자열 끝에 느낌표를 추가하고, @uppercase
는 문자열을 대문자로 변환합니다.
클래스 메서드를 위한 데코레이터
데코레이터는 클래스 메서드에서도 사용할 수 있습니다. 이는 클래스 내 메서드의 동작을 제어하고자 할 때 특히 유용합니다. 클래스 메서드에 데코레이터를 적용할 때 self
또는 cls
와 같은 인수에 유의해야 합니다.
1def log_method_call(func):
2 def wrapper(self, *args, **kwargs):
3 print(f"Calling method '{func.__name__}'...")
4 return func(self, *args, **kwargs)
5 return wrapper
6
7class MyClass:
8 @log_method_call
9 def greet(self, name):
10 print(f"Hello, {name}")
11
12obj = MyClass()
13obj.greet("Bob")
이 예제에서는 log_method_call
데코레이터가 greet
메서드에 적용되어 메서드 호출 시 로그를 출력합니다.
데코레이터 사용 시 주의사항
데코레이터 사용 시 고려해야 할 사항이 있습니다. 데코레이터가 원래 함수의 이름 및 문서화 문자열(e.g., __name__
또는 __doc__
)을 변경할 수 있으므로, functools.wraps
를 사용하여 이러한 정보를 보존하는 것이 좋습니다.
1import functools
2
3def my_decorator(func):
4 @functools.wraps(func)
5 def wrapper(*args, **kwargs):
6 print("Before the function call")
7 return func(*args, **kwargs)
8 return wrapper
@functools.wraps
를 사용하면 원래 함수의 메타데이터가 래퍼 함수로 올바르게 전달되도록 보장됩니다.
요약
Python 데코레이터는 함수와 메서드에 추가 기능을 간결하게 추가할 수 있는 매우 강력한 도구입니다. 데코레이터는 코드 중복을 줄이고 유지보수성과 재사용성을 향상시키기 위해 다양한 상황에서 사용할 수 있습니다. 데코레이터의 작동 방식을 이해하면 더 효율적이고 유연한 코드를 작성할 수 있습니다.
위의 기사를 보면서 Visual Studio Code를 사용해 우리 유튜브 채널에서 함께 따라할 수 있습니다. 유튜브 채널도 확인해 주세요.