ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [코딩도장] day29. 파이썬 데코레이터(2/2)
    IT/파이썬 2020. 9. 26. 16:14

    출처 : unsplash

     

    ■ 들어가기

    - 파이썬 코딩 도장 (남재윤/길벗). 을 공부하며 정리하는 블로그


    ▶ Unit42. 데코레이터 사용하기

         - 42.1 데코레이터 만들기

         - 42.2 매개변수와 반환값을 처리하는 데코레이터 만들기

         - 42.3 매개변수가 있는 데코레이터 만들기

         - 42.4 클래스로 데코레이터 만들기

         - 42.5 클래스로 매개변수와 반환값을 처리하는 데코레이터 만들기

     

     

     

    >> 42.3 매개변수가 있는 데코레이터 만들기 <<

    - 매개변수가 있는 데코레이터는 값을 지정해서 동작 바꿀 수 있음

    소스 (decorator_parameter.py) 결과
    def is_multiple(x) :    # 데코레이터가 사용할 매개변수 지정
        def real_decorator(func) :  # 호출할 함수를 매개변수로 받음
            def wrapper(a, b) :     # 호출할 함수의 매개변수와 똑같이 지정
                r = func(a, b)      # func를 호출하고 반환값을 변수에 저장
                if r % x == 0 :     # func의 반환값이 x의 배수인지 확인
                    print('{0}의 반환값은 {1}의 배수입니다.'.format(func.__name__, x))
                else :
                    print('{0}의 반환값은 {1}의 배수가 아닙니다.'.format(func.__name__, x))
                return r            # func의 반환값을 반환
            return wrapper          # wrapper 함수 반환
        return real_decorator       # real_decorator 함수 반환

    @is_multiple(3)                 # @데코레이터(인수)
    def add(a, b) :
        return a + b

    print(add(10, 20))
    print(add(2, 5))
    add의 반환값은 3의 배수입니다.
    30
    add의 반환값은 3의 배수가 아닙니다.
    7

    - 앞서 데코레이터 만들 때 함수 안에 함수를 하나만 만들었는데.

    - 매개변수가 있는 데코레이터를 만들 때는 함수를 하나 더 만들어야 함. 즉, 함수 2개 생성 필요

      def is_multiple    // 데코레이터 함수로 매개변수 x 지정

      def real_decorator     // 실제 데코레이터 역할하는 함수. 호출할 함수를 매개변수로 받음

      def wrapper       // 래퍼함수. 실제 호출할 함수와 동일한 매개변수 지정

     

     

    >> 42.4 클래스로 데코레이터 만들기 <<

    - 클래스로 데코레이터를 구현 시,

    1) 먼저 __init__ 메서드를 만들고 호출할 함수를 초깃값으로 받고

    2) 인스턴스를 함수처럼 호출하게 해주는 __call__ 메서드를 구현해야 함

    소스 (decorator_class.py) 결과
    class Trace :
        def __init__(self, func) :      # 호출할 함수를 인스턴스의 초깃값으로 받음
            self.func = func            # 호출할 함수를 속성 func에 저장

        def __call__(self) :
            print(self.func.__name__, '함수 시작')  # __name__으로 함수 이름 출력
            self.func()                             # 속성 func에 저장된 함수 호출
            print(self.func.__name__, '함수 끝')


    @Trace  # @데코레이터
    def hello() :
        print('hello')

    hello()     # 함수를 그대로 호출
    hello 함수 시작
    hello
    hello 함수 끝

     

     

    >> 42.5 클래스로 매개변수와 반환값을 처리하는 데코레이터 만들기 <<

    - 클래스로 만든 데코레이터도 매개변수와 반환값 처리 가능

    소스 (decorator_class_param_return.py) 결과
    class Trace :
        def __init__(self, func) :      # 호출할 함수를 인스턴스의 초깃값으로 받음
            self.func = func            # 호출할 함수를 속성 func에 저장

        def __call__(self, *args, **kwargs) :   # 호출할 함수의 매개변수를 처리
            r = self.func(*args, **kwargs)      # self.func에 매개변수를 넣어 호출한 뒤 반환값을 변수에 저장
            print('{0}(args={1}, kwargs={2}) -> {3}'.format(self.func.__name__, args, kwargs, r))
            return r


    @Trace      # @데코레이터
    def add(a, b) :
        return a + b


    print(add(10, 20))
    print(add(a=10, b=20))
    add(args=(10, 20), kwargs={}) -> 30
    30
    add(args=(), kwargs={'a': 10, 'b': 20}) -> 30
    30

    - 위의 예제에서는 위치 인수와 키워드 인수를 모두 처리하는 가변 인수로 구현하였으나

    - 고정된 매개변수를 사용할 때는 "def __call__(self, a, b) : " 처럼 구현 가능

     

    [REMIND] 위치 인수?

    - 함수에 인수를 순서대로 넣는 방식

    - 위치 인수를 사용하는 함수는 리스트(튜플) 앞에 *(애스터리스크)를 붙혀서 리스트 언패킹으로 넣을 수 있음

    def 함수이름(매개변수, 매개변수2) :        # 위치 인수를 사용하는 함수
        코드

    함수(*리스트)     # 리스트 언패킹
    함수(*튜플)        # 튜플 언패킹

    - 위치 인수를 사용하는 가변 인수 함수는 매개변수 앞에 *를 붙여서 만듦

    def 함수이름(*매개변수) :      # 위치인수를 사용하는 가변 인수 함수 (일반적으로 *args 형태로 작성, 타입: 튜플)
        코드

    함수(인수1, 인수2)     # 인수 여러 개를 직접 넣기
    함수(*리스트)           # 리스트 언패킹
    함수(*튜플)              # 튜플 언패킹

     

    [REMIND] 키워드 인수?

    - 함수에 넣는 인수에 이름(키워드)를 붙이는 방식

    - 키워드 인수는 딕셔너리 앞에 **(애스터리스크 두 개)를 붙여서 딕셔너리 언패킹으로 넣을 수 있음

    함수(키워드1=값1, 키워드2=값2)          # 함수를 키워드 인수 방식으로 호출

    함수(**딕셔너리)          # 딕셔너리 언패킹

    - 키워드 인수를 사용하는 가변 인수 함수는 매개변수 앞에 **를 붙여서 만듦

    def 함수이름(**매개변수) :     # 키워드 인수를 사용하는 가변 인수 함수 (일반적으로 **kwargs 형태로 작성, 타입: 딕셔너리)
        코드

    함수(키워드1=값1, 키워드2=값2)     # 키워드 인수를 직접 넣기
    함수(**딕셔너리)                          # 딕셔너리 언패킹

     

    1. 클래스로 매개변수가 있는 데코레이터 만들기

    소스 (decorator_class_parameter.py) 결과
    class IsMultiple :
        def __init__(self, x) :     # 데코레이터가 사용할 매개변수를 초깃값으로 받음
            self.x = x

        def __call__(self, func) :  # 호출할 함수를 매개변수로 받음
            def wrapper(a, b) :     # 호출할 함수의 매개변수와 똑같이 지정 (가변인수로 지정 가능)
                r = func(a, b)      # func를 호출하고 반환값을 변수에 저장
                if r % self.x == 0 :# func의 반환값이 self.x의 배수인지 확인
                    print('{0}의 반환값은 {1}의 배수입니다.'.format(func.__name__, self.x))
                else :
                    print('{0}의 반환값은 {1}의 배수가 아닙니다.'.format(func.__name__, self.x))
                return r            # func의 반환값을 반환
            return wrapper          # wrapper 함수 반환

    @IsMultiple(3)  # @데코레이터(인수)
    def add(a, b) :
        return a + b
    print(add(10, 20))
    print(add(2, 5))
    add의 반환값은 3의 배수입니다.
    30
    add의 반환값은 3의 배수가 아닙니다.
    7

    - 보통 데코레이터는 프로그램의 버그를 찾는 디버깅, 함수의 성능 측정, 함수 실행 전에 데이터 확인 등에 활용됨

     

     

    댓글

Designed by Tistory.