728x90

Python FastAPI를 공부하면서 데코레이터를 알게 되었는데 왜 어떻게 작동하는지 잘 이해가 가지 않아서 공부를 하게 되었고 이에 대해 내가 알게된 점에 대해 소개해보려고 한다. 코드는 여기에서 확인할 수 있다.
데코레이터란 무엇인가?
데코레이터는 파이썬의 고급 기능 중 하나로, 함수나 메서드에 코드를 수정하지 않고 기능을 주입하는 방법입니다. 함수를 여러 기능으로 사용해야 하며 코드에 수정을 가하지 않을 때 자주 사용한다. 데코레이터는 함수로 인자를 받고, 함수를 감싸는 래퍼(wrapper)를 정의하여, 함수에 추가적인 기능을 할 수 있도록 한다.
데코레이터를 사용하는 이유는?
사용하는데 여러가지 이유가 있다.
- 코드 재사용 : 코드가 중복될 때 함수를 사용하는데 이때 함수를 여러 방법으로 사용하기 위해 데코레이터를 사용한다.
- 기능 확장 : 기존 코드에 추가적인 기능을 추가하기 위해서 사용한다.
- 래퍼 함수에 대한 제어 : 데코레이터 내부의 함수를 제어하기 위해 사용한다.
데코레이터의 구조
데코레이터 함수
데코레이터의 함수 구조는 다음과 같다.
def simple_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
@simple_decorator
def say_hello():
print("Hello!")
say_hello()
'''
Something is happening before the function is called.
Hello!
Something is happening after the function is called.
'''
@인자를 사용하여 표현한 데코레이터이다. 함수를 @로 바꾸어 함수를 간단하게 표현한다.
데코레이터 함수 내부에는 wrapper함수를 써야한다. 이름은 무관하지만 내부에 함수를 정의해야하며, return값은 내부에 정의한 함수를 써야한다.
위의 코드는 데코레이터를 쓰지 않으면 다음과 같이 표현할 수 있다.
def simple_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
def say_hello():
print("Hello!")
# 데코레이터를 수동으로 적용
decorated_say_hello = simple_decorator(say_hello)
# 함수 호출
decorated_say_hello()
'''
Something is happening before the function is called.
Hello!
Something is happening after the function is called.
'''
데코레이터 클래스
데코레이터 클래스 구조는 다음과 같다.
class SimpleDecorator:
def __init__(self, func):
self.func = func
def __call__(self):
print("Something is happening before the function is called.")
self.func()
print("Something is happening after the function is called.")
@SimpleDecorator
def say_hello():
print("Hello!")
say_hello()
'''
Something is happening before the function is called.
Hello!
Something is happening after the function is called.
'''
클래스가 실행되는 것에 대해 설명은 다음과 같다.
- SimpleDecorator 클래스는 __init__ 메서드에서 데코레이터가 감싸야 할 함수를 인자로 받아 저장한다.
- __call__ 메서드는 데코레이터가 적용된 함수가 호출될 때 실행된다.
- @SimpleDecorator를 사용하여 say_hello 함수에 데코레이터를 적용하면, say_hello 함수가 호출될 때 SimpleDecorator 클래스의 __call__ 메서드가 실행된다.
데코레이터 예시
여기서는 함수에 대해 예시 3개에 대해 설명한다.
- 실행시간 측정
- 파라미터 전달
- 디버깅
실행 시간 측정
데코레이터 사용
import time
def timer(func):
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
print(f"{func.__name__} took {end_time - start_time:.4f} seconds")
return result
return wrapper
@timer
def slow_function(delay_time):
time.sleep(delay_time)
slow_function(1)
'''
slow_function took 1.0007 seconds
'''
데코레이터 없이 사용
import time
def slow_function(delay_time):
start_time = time.time()
time.sleep(delay_time)
end_time = time.time()
print(f"slow_function took {end_time - start_time:.4f} seconds")
return "Done"
slow_function(1)
'''
slow_function took 1.0007 seconds
'''
파라미터 전달
데코레이터 사용
def repeat(num_times):
def decorator_repeat(func):
def wrapper(*args, **kwargs):
for _ in range(num_times):
result = func(*args, **kwargs)
return result
return wrapper
return decorator_repeat
@repeat(num_times=3)
def greet(name):
print(f"Hello {name}")
greet("Alice")
데코레이터 없이 사용
def repeat(num_times):
def decorator_repeat(func):
def wrapper(*args, **kwargs):
for _ in range(num_times):
result = func(*args, **kwargs)
return result
return wrapper
return decorator_repeat
def greet(name):
print(f"Hello {name}")
# 데코레이터를 수동으로 적용
decorated_greet = repeat(num_times=3)(greet)
# 함수 호출
decorated_greet("Alice")
디버깅
데코레이터 사용
def debug(func):
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
print(f"{func.__name__} called with {args}, {kwargs} returned {result}")
return result
return wrapper
@debug
def make_greeting(name, age=None):
greeting = f"Hello {name}"
if age:
greeting += f", you are {age} years old!"
return greeting
make_greeting("Alice", age=30)
'''
make_greeting called with ('Alice',), {'age': 30} returned Hello Alice, you are 30 years old!
'''
데코레이터 없이 사용
def make_greeting(name, age=None):
greeting = f"Hello {name}"
if age:
greeting += f", you are {age} years old!"
print(f"make_greeting called with ({name}, {age}) returned {greeting}")
return greeting
make_greeting("Alice", age=30)
'''
make_greeting called with ('Alice',), {'age': 30} returned Hello Alice, you are 30 years old!
'''
'Coding > Python' 카테고리의 다른 글
[Python] 'Fatal error in launcher: Unable to create process using' 오류 해결 방법 (0) | 2024.06.04 |
---|---|
[Python] Progress Bar(tqdm)을 깔끔하게 출력하는 방법은 무엇일까? (0) | 2024.05.30 |
[Python] pydantic에 대해 알아보자 (0) | 2024.04.21 |
[Python] Docstring에 대해 알아보자 (0) | 2024.04.16 |
[Python] tqdm - Python에서 진행률을 시각적으로 표시 (0) | 2024.03.20 |