[Python] Decorator (2)

2 minute read

python-version-3.7.1

Decorator (2)

Deoorator 의 기본적인 것은 Decorator 1 에서 다루었으니 참고하길 바란다.

[Python] Decorator (1)


Step. 1

def deco_func(origin_func):  # 데코레이터 함수
    def nested_func(*args, **kwargs):
        print("계산 시작합니다.")
        origin_func(*args, **kwargs)
        print("계산 완료되었습니다.")
        return

    return nested_func

@deco_func
def output(a, b):
    print(a + b)

[Python] Decorator (1) 에서 사용했던 예시코드이다.
위 코드에서의 불완전 요소는 값을 반환받지 못한다는 점이다.

output(3,7)

>>> '계산 시작합니다.'
>>> '10'
>>> '계산 완료되었습니다.'

type(output(3,7))

>>> NoneType

output 함수의 결과는 아무런 값도 반환받지 못한다. return을 통해 반환받은 값이 없기 때문이다.


Step. 2

위의 문제를 해결하기 위해서
output 함수의 printreturn으로 바꾼다.

def deco_func(origin_func):  # 데코레이터 함수
    def nested_func(*args, **kwargs):
        print("계산 시작합니다.")
        origin_func(*args, **kwargs)
        print("계산 완료되었습니다.")
        return

    return nested_func

@deco_func
def output(a, b):
    return(a + b) # print 에서 return 으로 변환
output(3,7) # 함수 실행

>>> '계산 시작합니다.'
>>> '계산 완료되었습니다.'

type(output(3,7))

>>> NoneType

현재 문제점

  1. 계산 시작과 완료 사이에 결과값이 출력되지 않았다.
  2. output(3,7)의 값이 여전히 NoneType 이다.

원인

deco_func 함수의 중첩함수 nested_func 내부에서 output 함수가 실행되고 return 이 됨에따라 반환은 되었다.
하지만 반환된 곳은 nested_func 함수 내부이며, nested_func 는 어떤 값도 반환하지 않았다.
이에따라 output 함수의 값은 최종적으로 반환되지 못한다.
이 문제를 해결하기 위해서는 nested_func 함수 내부에서 origin_func(*args, **kwargs) 를 반환해주어야 한다는 것을 알 수 있다.


문제를 해결하기 위한 실험코드

def deco_func(origin_func):  # 데코레이터 함수
    def nested_func(*args, **kwargs):
        print("계산 시작합니다.")
        return origin_func(*args, **kwargs)  # return 이 중간에 위치함에 따라 아래코드는 실행되지 못한다.
        print("계산 완료되었습니다.")
        
    return nested_func

@deco_func
def output(a, b):
    return a + b
output(3, 7)

>>> '계산 시작합니다.'

type(output(3,7))  # 값을 반환받았는지 확인해보자.

>>> int

문제점

  1. return 이 코드 중간에 위치함에 따라
    return 뒤에 위치한 print("계산 완료되었습니다.") 코드는 실행조차 되지않았다.
  2. 결과값 10 이 “계산 시작합니다.” 뒤에 출력되지 않았다.
    그러나 결과값 10 은 output(3,7) 이 반환받았다.


Step.3

해결해야할 사항 구체화

  • output함수의 반환값을 print("계산 시작합니다.")print("계산 완료되었습니다")코드 사이에서 프린트한다.

  • output함수의 반환값을 nested_func 에서 최종적으로 반환시켜야 한다.

def deco_func(origin_func):  # 데코레이터 함수
    def nested_func(*args, **kwargs):
        print("계산 시작합니다.")
        print(origin_func(*args, **kwargs))  # 함수 결과값 print 프린트
        print("계산 완료되었습니다.")
        return origin_func(*args, **kwargs)  # 함수 결과값 반환
        
    return nested_func

@deco_func
def output(a, b):
    return a + b

이제 결과값을 살펴보자.

output(3,7)

>>> '계산 시작합니다.'
>>> '10'
>>> '계산 완료되었습니다.'

값 반환여부 확인

result = output(3,7)
type(result)

>>> int

print(result)

>>> 10

결과값이 변수에 문제없이 할당된다.


Step. Final

하지만 위의 코드에서는 origin_func두번 실행했다는 점에서 효율적이지 못하다.
따라서 origin func 의 결과값을 변수로 저장한 뒤, printreturn 을 해주는 방식으로 코드를 개선해보겠다.

def deco_func(origin_func):  # 데코레이터 함수
    def nested_func(*args, **kwargs):
        print("계산 시작합니다.")
        result = origin_func(*args, **kwargs)  # 함수의 결과값 변수에 할당
        print(result) # 결과값 프린트
        print("계산 완료되었습니다.")
        return result  # 결과값 반환
        
    return nested_func

@deco_func
def output(a, b):
    return a + b

Leave a comment