728x90
반응형

<데코레이터(Decorator)>

- 대량 데이터 처리할때 사용

- wrapper는 한번 사용 하면 없어지므로 대용량 데이터에 대해 return으로 결과 값만 받아와서 사용
- 함수의 재사용성을 확장한 개념의 방법
- 자바의 오버라이드와 비슷한 개념


<함수 실행 시간 확인하는 데코레이터 프로그래밍 작성>

 

### 데코레이터 함수 정의하기
- func : 실제 처리할 함수 받아오는 매개 변수
- 외부에 있는 처리하고하 하는 함수가 func로 들어와야 함

- *args : 함수에 임의의 개수의 위치 인자를 전달할 때 사용한다. 함수 정의에서 *args는 튜플로 위치 인자들을 받는다. 이를 통해 함수는 몇 개의 위치 인자가 전달되든지 처리할 수 있다.

- **kwargs : 함수에 임의의 개수의 키워드 인자를 전달할 때 사용한다. 함수 정의에서 **kwargs는 딕셔너리로 키워드 인자들을 받는다. 이를 통해 함수는 몇 개의 키워드 인자가 전달되든지 처리할 수 있다.

def timer_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 : end_time = {end_time}")
        return rs
    print("#5---------------")    
    return wrapper

 

### 데코레이터 호출 및 처리할 함수 정의하기

- 데코레이터 호출은 @로 사용함

- 데코레이터 함수 호출 시 및에 정의된 함수(exe_function)가 자동으로 전달 됨
- 매개변수 func은  메모리로 exe_function의 주소값을 이용
- 데코레이터 함수가 리턴한 wrapper함수는 exe_function이 된다. 즉, wrapper가 exe_function로 재정의 된다.
- 맨 처음 함수는 3개. 주소도 3개 그러나 재정의 할 경우 exe_function의 주소는 wrapper의 주소로 바뀜

# (재정의 되는 시점)
@timer_decorator 
def exe_function() : 
    print("실제 처리할 함수")
    ### 2초간 대기 : 데코레이터가 처리되는 시간을 벌어주기 위해서 
    time.sleep(2)
#1 : func = <function exe_function at 0x00000113C2EE1F80>
#5---------------

 

### 실제 처리하기

exe_function()
#2 : start_time = 1699930626.0731795
실제 처리할 함수
#3 : rs = None
#4 : end_time = 1699930628.0737495

<로그 데코레이터>

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 0x00000113C3148B80>
#2-------------

 

### 처리함수 호출

another_function()
Logo : another_function 함수 호출됨
집에 가고싶다
Logo : another_function 함수 종료됨

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

# 함수 총 4개 사용
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(f"#6 -----------")
        return wrapper
    print(f"#7 -----------")
    return decorator

 

### 데코레이터 호출 및 처리함수 정의

@check_permission(param_id="admin")
def admin_function(re_msg) :
    print(f"인증 결과 : {re_msg}")
#1: param_id = admin
#7 -----------
#2: func = <function admin_function at 0x00000113C398B560>
#6 -----------

 

### 처리함수 호출

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

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

- 함수이름 자유롭게 생성

- 데코레이터 함수 생성해서 대문자로 출력하기

 

작성해본 코드

def change_lang(func) :
    def lang_decorator(char1, char2) :
        char1_upper = char1.upper()
        char2_upper = char2.upper()
        result = func(char1_upper, char2_upper)

        return result
    return lang_decorator

@change_lang
def change_function(char1, char2) : 
    print(f"첫 번째 문자: {char1}")
    print(f"두 번째 문자: {char2}")

change_function('abcd', 'efgh')
첫 번째 문자: ABCD
두 번째 문자: EFGH

 

강사님 코드

def decorator_upper(func) :
    # args : 값 여러개 받음
    # kwargs : 리스트, 딕셔너리 받음
    ### 인자로 넘어온 2개의 소문자는 args 매개변수가 받게됨
    def wrapper(*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

 

데코레이터 실행 과정 이해하기

@decorator_upper가 실행 되면 getUpper함수가 같이 실행되면서

decorator_upper 주소 만들어지고 wrapper 주소 만들어짐
getUpper의 주소도 동시에 만들어졌지만 decorator_upper  호출되는 순간 getUpper 를 변수인 func에 넣게 됨
func는 getUpper의 주소를 갖는 변수가 된다
그때 return wrapper 하면 getUpper 가 바라보는 주소를 wrapper주소로  바꿔버림
wrapper 안에서 호출되는 func은  getUpper 의 주소를 받아서 갖고 있기 때문에 wrapper 에서 func의 원본인 getUpper 함수에 변수를 넣어 사용할 수 있는 것


<실습> 어제 작성한 도서관리 프로그램에 데코레이터를 적용하기

https://mzero.tistory.com/42

 

[Python] 파이썬 도서 관리 프로그램 만들기 실습 2

주제 : 도서 입고/대출/반납 관리를 위한 키오스크 파이썬 프로그램 실습 1. 주요내용 : 실습1에서 작성한 도서 관리 프로그램에 데코레이터를 적용하기 데코레이터 추가한 코드 ### 기능을 수행

mzero.tistory.com

 

728x90
반응형

+ Recent posts