decorate : 장식하다, 꾸미다
파이썬은 데코레이터라는 강력한 기능을 지원합니다.
가끔 레퍼런스 코드를 검색하다 @staticmethod
, @classmethod
와 같은 코드를 보식 적이 있을 겁니다. @
로 시작하는 것이 바로 데코레이터인데요,
함수 앞에 장식을 한다고 해서 데코레이터라는 이름이 붙은겁니다.
그럼 지금부터 데코레이터에 대해 더 자세히 알아보도록 하겠습니다.
파이썬에서 데코레이터를 구현할 때 아래의 형식을 따릅니다.
1) 데코레이터 함수 정의
2) 내부 함수 정의
3) @
기호 사용
@
기호와 함께 데코레이터 이름을 함수 정의 전에 붙입니다.데코레이터는 꼭 하나만 사용할 수 있는 것이 아니라, 여러 개도 사용 가능합니다.
데코레이터를 사용했을 시, 코드 중복을 줄이고, 비즈니스 로직과 인증 로직을 분리하여 각 함수의 가독성과 유지 관리성을 향상시킵니다.
글로만 보면 살짝 어려운데요, 예시를 통해 보겠습니다.
예시는 하나만 사용했을 때를 보여드리겠습니다.
아래의 예시는 say_hello
함수의 시작과 끝에 my_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()
위의 예제를 실행을 하면 아래와 같은 출력이 나옵니다.
Something is happening before the function is called.
Hello!
Something is happening after the function is called.
예시에 대해 더 자세하게 설명드리겠습니다.
1) 데코레이터 함수 정의 (my_decorator
)
my_decorator
는 데코레이터 함수로 func
를 인자로 받습니다. 여기서 func
는 데코레이터에 의해 감싸질 원본 함수입니다.2) 중첩 함수 (wrapper
)
3) 데코레이터 적용 (@my_decorator
)
@my_decorator
는 say_hello
함수 정의 바로 위에 위치하며, 이는 say_hello
함수가 my_decorator
에 의해 자동으로 감싸진다는 것을 의미합니다.say_hello()
를 호출할 때 실제로 호출되는 함수는 wrapper()
이며, say_hello()
내부의 코드는 wrapper()
내에서 func()
를 호출함으로써 실행됩니다.4) 함수 호출 (say_hello()
)
say_hello()
를 호출합니다. 이 호출은 실제로 wrapper
함수를 실행하고, 그 결과 say_hello
함수 내의 코드가 wrapper
함수에 의해 정의된 전후 컨텍스트에서 실행됩니다.그림으로 보자면 아래와 같습니다.
위의 그림은 파이썬 코딩도장의 그림을 참고하였습니다.
데코레이터는 로깅, 성능 측정, 트랜잭션 처리, 접근 제어 등의 다양한 상황에서 활용될 수 있습니다.
가장 대표적인 사례로는 웹 애플리케이션에서 API 엔드포인트에 대한 접근 제어인데요.
사용자의 인증 상태를 검증하거나 특정 권한을 확인하여 요청을 처리하기 전에 접근 권한을 확인할 때 데코레이터를 많이 사용합니다.
위의 사례에 대한 코드를 보여드리겠습니다.
아래는 Flask 웹 프레임워크를 사용한 예제로, 로그인한 사용자만 특정 페이지에 접근할 수 있도록 하는 데코레이터입니다.
from flask import Flask, session, redirect, url_for
from functools import wraps
app = Flask(__name__)
# 로그인을 한 상태인지 확인하는 데코레이터
def login_required(f):
@wraps(f)
def decorated_function(*args, **kwargs):
if 'logged_in' not in session: # 세션에 로그인 상태 정보가 없으면
return redirect(url_for('login')) # 로그인 페이지로 리다이렉트
return f(*args, **kwargs)
return decorated_function
# 페이지에 접근하기 전, login_required를 호출하여 사용자가 로그인을 했는지 확인
@app.route('/')
@login_required
def secret_page():
return "This is a secret page. Only authenticated users can see this."
# 사용자를 간단하게 로그인 상태로 설정
@app.route('/login')
def login():
session['logged_in'] = True # 실제로는 사용자 인증 후 세션에 추가
return "You are now logged in."
if __name__ == '__main__':
app.secret_key = 'your_secret_key'
app.run(debug=True)
지금까지 데코레이터에 대해 알아보았습니다!
어려울 줄 알았는데 데코레이터도 막상 보면 어렵지 않은 개념입니다 :)