[Python] Decorators

미남잉·6일 전
0

유튜브 강의를 듣고 정리하였습니다.

출처: 유튜브 - Decorators - Advanced Python Tutorial #2

1️⃣ 데코레이터가 필요한 이유?

✔ 반복되는 코드 제거

예를 들어, 로그인 체크, 권한 확인, 로깅 등을 여러 함수에 적용할 때 코드 중복을 줄일 수 있습니다.

✔ 가독성 향상

코드가 더 깔끔하고 이해하기 쉬워집니다.

✔ 분리된 유지보수

기존 함수의 코드를 직접 수정하지 않고도 새로운 기능을 추가할 수 있습니다.

2️⃣ 데코레이터 기본 구조

데코레이터는 보통 함수를 감싸는 함수(wrapper)를 사용해 구현합니다.

def mydecorator(function):
    def wrapper():
        print("I am decorating your function!")
        function()  # 원래 함수 실행
    return wrapper

def hello_world():
    print("Hello World")
    
decorated_hello = mydecorator(hello_world)  # 데코레이터 적용
decorated_hello()

📌 실행 결과

I am decorating your function!
Hello World

✔ mydecorator(hello_world)는 wrapper 함수를 반환합니다.
✔ wrapper()가 실행되면서 추가적인 동작(출력)이 먼저 실행된 후, 원래 함수(hello_world())가 호출됩니다.

3️⃣ @데코레이터 문법 사용

Python에서는 @데코레이터명을 사용하면 더 간결하게 적용할 수 있습니다.

def mydecorator(function):
    def wrapper():
        print("I am decorating your function!")
        function()
    return wrapper

@mydecorator
def hello_world():
    print("Hello World")
    
hello_world()

@mydecorator를 사용하면 hello_world = mydecorator(hello_world)와 같은 효과를 가집니다.
hello_world()를 실행하면 자동으로 데코레이터가 적용된 상태로 실행됩니다.

4️⃣ 인자(*args, **kwargs)를 받는 데코레이터

위 예제는 인자를 받지 않는 함수에만 사용할 수 있습니다.
함수에 인자를 전달하려면 *args, **kwargs를 사용해야 합니다.

def mydecorator(function):
    def wrapper(*args, **kwargs):
        print("I am decorating your function!")
        return function(*args, **kwargs)  # 원래 함수 실행 후 결과 반환
    return wrapper

@mydecorator
def hello(person):
    print(f"Hello {person}")
    
hello("Mike")

✔ wrapper(*args, *kwargs)가 모든 인자를 받아서 function(args, **kwargs)로 전달합니다.
✔ hello("Mike") 실행 시 "Hello Mike"가 출력됩니다.

5️⃣ 함수의 반환값을 유지하는 데코레이터

데코레이터가 적용된 함수가 반환값을 갖는 경우, wrapper()도 원래 함수의 반환값을 반환해야 합니다.

def mydecorator(function):
    def wrapper(*args, **kwargs):
        return_value = function(*args, **kwargs)  # 원래 함수 실행
        print("I am decorating your function!")
        return return_value  # 원래 함수의 결과 반환
    return wrapper

@mydecorator
def hello(person):
    print(f"Hello {person}")
    return f"Hello {person}!"

print(hello("Mike"))  

✔ 원래 함수의 반환값을 return_value에 저장한 후 반환합니다.
✔ 따라서 print(hello("Mike")) 실행 시 "Hello Mike!"가 출력됩니다.

예제 1 - 함수 실행 시간 측정

import time

def timed(function):
    def wrapper(*args, **kwargs):
        start_time = time.time()  # 시작 시간
        result = function(*args, **kwargs)  # 원래 함수 실행
        end_time = time.time()  # 종료 시간
        print(f"{function.__name__} took {end_time - start_time:.5f} seconds")
        return result
    return wrapper

@timed
def compute_factorial(n):
    result = 1
    for i in range(1, n + 1):
        result *= i
    return result

compute_factorial(10000)

✔ 실행 시간을 측정하고 출력해주는 데코레이터
✔ compute_factorial(10000) 실행 시 took X.XXXXX seconds가 출력됨

예제 2 - 로그 기록

def logged(function):
    def wrapper(*args, **kwargs):
        value = function(*args, **kwargs)  # 원래 함수 실행
        with open("logfile.txt", "a+") as f:
            fname = function.__name__
            f.write(f"{fname} returned value {value}\n")  # 결과를 파일에 기록
        return value
    return wrapper

@logged
def add(x, y):
    return x + y

print(add(10, 20))  

✔ logfile.txt에 "add returned value 30"이 저장됨
✔ print(add(10, 20)) 실행 시 결과 30이 출력됨

예제 3 - 권한 체크

def requires_admin(function):
    def wrapper(user_role, *args, **kwargs):
        if user_role != "admin":
            print("Access denied: Admins only")
            return
        return function(*args, **kwargs)
    return wrapper

@requires_admin
def delete_database():
    print("Database deleted!")

delete_database("user")  # Access denied
delete_database("admin")  # 실행됨

✅ 데코레이터는 기존 코드를 수정하지 않고 기능을 추가하는 강력한 도구
✅ @데코레이터 문법을 사용하면 깔끔한 코드 작성 가능
✅ 실행 시간 측정, 로깅, 권한 체크 등 다양한 실전 활용 가능

profile
Computer Vision Engineer

0개의 댓글

관련 채용 정보