데코레이터 개념 소개

Beginner

This tutorial is from open-source community. Access the source code

소개

이 섹션에서는 데코레이터 (decorator) 의 개념을 소개합니다. 이는 고급 주제이므로 여기서는 기본적인 내용만 다룹니다.

이것은 가이드 실험입니다. 학습과 실습을 돕기 위한 단계별 지침을 제공합니다.각 단계를 완료하고 실무 경험을 쌓기 위해 지침을 주의 깊게 따르세요. 과거 데이터에 따르면, 이것은 중급 레벨의 실험이며 완료율은 77%입니다.학습자들로부터 100%의 긍정적인 리뷰율을 받았습니다.

로깅 예시

함수를 생각해 봅시다.

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

이제, 로깅 (logging) 이 추가된 함수를 생각해 봅시다.

def add(x, y):
    print('Calling add')
    return x + y

이제 두 번째 함수도 로깅이 추가되었습니다.

def sub(x, y):
    print('Calling sub')
    return x - y

관찰

관찰: 다소 반복적입니다.

코드 복제가 많은 프로그램을 작성하는 것은 종종 매우 짜증나는 일입니다. 작성하기 번거롭고 유지 관리하기 어렵습니다. 특히 작동 방식을 변경하려는 경우 (예: 다른 종류의 로깅) 더욱 그렇습니다.

로깅을 만드는 코드

아마도 로깅이 추가된 함수를 만드는 함수를 만들 수 있을 것입니다. 래퍼 (wrapper) 입니다.

def logged(func):
    def wrapper(*args, **kwargs):
        print('Calling', func.__name__)
        return func(*args, **kwargs)
    return wrapper

이제 사용해 봅시다.

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

logged_add = logged(add)

logged에 의해 반환된 함수를 호출하면 어떻게 될까요?

logged_add(3, 4)      ## You see the logging message appear

이 예제는 소위 래퍼 함수를 생성하는 과정을 보여줍니다.

래퍼는 다른 함수를 감싸서 추가적인 처리를 수행하지만, 그렇지 않으면 원래 함수와 정확히 동일한 방식으로 작동하는 함수입니다.

>>> logged_add(3, 4)
Calling add   ## Extra output. Added by the wrapper
7
>>>

참고: logged() 함수는 래퍼를 생성하고 결과를 반환합니다.

데코레이터 (Decorators)

함수 주위에 래퍼를 사용하는 것은 Python 에서 매우 흔합니다. 너무 흔해서, 이를 위한 특별한 구문이 있습니다.

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

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

특별한 구문은 위에서 보여준 것과 정확히 동일한 단계를 수행합니다. 데코레이터는 단지 새로운 구문일 뿐입니다. 함수를 *데코레이트 (decorate)*한다고 말합니다.

해설

여기에 제시된 것보다 데코레이터에는 훨씬 더 미묘한 세부 사항이 많이 있습니다. 예를 들어, 클래스에서 사용하는 경우나, 함수와 함께 여러 데코레이터를 사용하는 경우 등이 있습니다. 하지만 이전 예제는 데코레이터의 사용이 어떻게 발생하는지를 잘 보여줍니다. 일반적으로, 광범위한 함수 정의에서 반복적인 코드가 나타나는 것에 대한 대응으로 사용됩니다. 데코레이터는 해당 코드를 중앙 정의로 이동시킬 수 있습니다.

연습 문제 7.10: 시간 측정을 위한 데코레이터

함수를 정의하면, 해당 함수의 이름과 모듈은 __name____module__ 속성에 저장됩니다. 예를 들어:

>>> def add(x,y):
        return x+y

>>> add.__name__
'add'
>>> add.__module__
'__main__'
>>>

timethis.py 파일에서, 함수가 실행되는 데 걸리는 시간을 출력하는 추가적인 로직 레이어로 함수를 감싸는 데코레이터 함수 timethis(func)를 작성하십시오. 이를 위해, 다음과 같이 시간 측정 호출로 함수를 감싸야 합니다:

start = time.time()
r = func(*args,**kwargs)
end = time.time()
print('%s.%s: %f' % (func.__module__, func.__name__, end-start))

다음은 데코레이터가 작동하는 방식의 예입니다:

>>> from timethis import timethis
>>> @timethis
def countdown(n):
    while n > 0:
        n -= 1

>>> countdown(10000000)
__main__.countdown : 0.076562
>>>

토론: 이 @timethis 데코레이터는 모든 함수 정의 앞에 배치될 수 있습니다. 따라서 성능 튜닝을 위한 진단 도구로 사용할 수 있습니다.

요약

축하합니다! 함수 데코레이터 (Function Decorators) 랩을 완료했습니다. LabEx 에서 더 많은 랩을 연습하여 실력을 향상시킬 수 있습니다.