코딩헤딩

python 알고리즘 기초3 데코레이터(Decorator) 본문

python

python 알고리즘 기초3 데코레이터(Decorator)

멈머이 2023. 11. 15. 23:37
728x90

'Bard'에게 파이썬에서 데코레이터를 왜 쓰는지 물어보았다.

"1. 데코레이터를 사용하면 함수의 기능을 확장하거나 변경하는 코드를 함수와 분리할 수 있습니다. 이렇게 하면 함수의 코드를 변경하지 않고도 필요한 기능을 추가하거나 수정할 수 있어 코드 재사용성을 높일 수 있습니다.

2. 데코레이터를 사용하면 함수의 기능을 확장하거나 변경하는 코드를 함수의 본문에서 분리하여 코드 가독성을 높일 수 있습니다.

3. 데코레이터를 사용하면 함수의 기능을 확장하거나 변경하는 코드와 함수의 기본 기능을 담당하는 코드를 분리하여 관심사의 분리를 높일 수 있습니다. "라고 한다.

 

데코레이터 호출은 "@"를 사용함.

이제부터 데코레이터를 사용한 프로그램을 작성해 보겠다.

1. 함수 실행 시간 확인하는 프로그램 작성

import time
### 데코레이터 함수 정의하기
# - func : 실제 처리할 함수 받아오는 매개변수
# - func = 아래 exe_function의 주소값
def time_decorator(func):
    print(f"#1 : func = {func}")
    
    ### 실제 실행될 함수 정의(함수 이름은 자유롭게)
    # - func로 받은 함수를 아래 함수로 재정의 하기
    def wrapper(*args, **kwargs):
        # - 시작시간
        start_time = time.time()
        print(f"#2 : start_time = {start_time}")

        ### 실제 처리할 함수 : func
        rs = func(*args, **kwargs)
        print(f"#3 : rs = {rs}")
        
        # - 종료시간
        end_time = time.time()
        print(f"#4 : endend_time = {end_time}")

        return rs
    print("#5---------------------")
    return wrapper
### 데코레이터 호출 및 처리할 함수 정의하기
# - 데코레이터 호출은 "@"를 사용함
# - 데코레이터 함수 호춯 시 밑에 정의된 함수(exe_function)가 자동으로 전달
# - 데코레이터 함수가 리턴한 wrapper 함수는 exe_function이 된다.
# - (재정의 되는 시점)
@time_decorator
def exe_function():
    print("실제 처리할 함수")
    ### 2초간 대기 : 데코레이터가 처리되는 시간을 벌어주기 위해서
    time.sleep(2)

결과 : #1 : func = <function exe_function at 0x000001 A97 E86 D800>

           #5---------------------

### 실제 처리하기
exe_function()

결과 : #2 : start_time = 1700058040.3923945
          실제 처리할 함수

---------------------------------2초 뒤 실생----------------------------------------
          #3 : rs = None
          #4 : endend_time = 1700058042.3931246

클로저 함수와 마찬가지로 중간중간 값을 찍어보면 가장 바깥의 함수인 껍데기가 실행되며 내부의 함수인 wrapper가 exe_function이 된다. wrapper가 실행된 후 time.sleep()가 작동하며 2초뒤 나머지 값까지 출력된다.

 

 

2. 로그 데코레이터

def log_decorator(func):
    print(f"#1 : func = {func}")
    def wrapper(*args, **kwargs):
        print(f"Logo : {func.__name__} 함수 호출됨")
        rs = func(*args, **kwargs)
        print(f"Logo : {func.__name__} 함수 호출됨")
        return rs
    print("#2-----------------------")    
    return wrapper
### 데코레이터 후출 및 처리함수 정의
@log_decorator
def another_function():
    print("여긴 어디? 넌 누구?")

결과 : #1 : func = <function another_function at 0x0000021F7FCD7E20>

           #2-----------------------

### 처리함수 호출
another_function()

결과 : Logo : another_function 함수 호출됨
          여긴 어디? 넌 누구?
           Logo : another_function 함수 호출됨

 

 

3. 데코레이터 내부함수에서 처리된 결과를 받아보기

def check_permission(param_id):
    print(f"#1 : param_id = {param_id}")
    
    def decorator(func):
        print(f"#2 : func = {func}")
        
        def wrapper(*args, **kwargs):
            check_id = "admin"
            print(f"#3 : check_id = {check_id}")

            if check_id == param_id:
                args = ["인증성공"]
                print(f"#4 : args = {args}")
                
                return func(*args, **kwargs)

            else:
                print(f"#5 : raise명령으로 강제 오류 발생시킴 ----------------")
                raise PermissionError("접근불가")  # ---------> 강제로 오류발생시킨다.
        print("#6------------------------------------")
        return wrapper
    print("#7--------------------------------")
    return decorator
### 데코레이터 호출
@check_permission(param_id = "admin")
def admin_function(rs_msg):
    print(f"인증결과 : {rs_msg}")

결과 : #1 : param_id = admin
          #7--------------------------------
          #2 : func = <function admin_function at 0x0000021F00A21120>
          #6------------------------------------

### 처리함수 호출
admin_function()

결과 : #3 : check_id = admin
          #4 : args = ['인증성공']
          인증결과 : 인증성공

 

 

4. 영문 소문자 2개를 매개변수로 받아서 대문자로 변환하는 데코레이터 프로그램

# - 데코레이터 함수 생성해서 대문자로 출력
def decorator_upper(func):
    ### 인자로 넘어온 2개의 소문자는 args 매개변수가 받게됨
    def wrapper(*args, **kwargs):  # args 값여러개 kwargs 리스트 딕셔너리 여러개
        ### 인자로 넘겨받은 2개의 소문자를 대문자로 처리하는 영역
        args = [arg.upper() for arg in args]
        ### 대문자로 변환된 값 2개를 args에 리스트 타입으로 담아서 넘기면 됨
        return func(*args, **kwargs)
    return wrapper
#데코레이터 호출 및 처리함수 정의
@decorator_upper
def getUpper(param1, param2):
    print(f"대문자로 변환된 {param1} / {param2}")
### 처리하는 함수 호출 : 소문자 2개를 인자로 넘겨주기
getUpper("abcd", "efgh")

결과 : 대문자로 변환된 ABCD / EFGH

728x90