Python의 데코레이터
데코레이터 프로그래머가 함수나 클래스의 동작을 수정할 수 있도록 하기 때문에 Python의 매우 강력하고 유용한 도구입니다. 데코레이터를 사용하면 래핑된 함수를 영구적으로 수정하지 않고도 래핑된 함수의 동작을 확장하기 위해 다른 함수를 래핑할 수 있습니다. 하지만 데코레이터에 대해 자세히 알아보기 전에 데코레이터를 학습하는 데 도움이 되는 몇 가지 개념을 이해해 보겠습니다.
일류 개체
파이썬에서 함수는 일류 물건 이는 Python의 함수를 인수로 사용하거나 전달할 수 있음을 의미합니다.
일급 함수의 속성:
- 함수는 객체 유형의 인스턴스입니다.
- 함수를 변수에 저장할 수 있습니다.
- 함수를 다른 함수에 매개변수로 전달할 수 있습니다.
- 함수에서 함수를 반환할 수 있습니다.
- 해시 테이블, 목록 등과 같은 데이터 구조에 저장할 수 있습니다.
더 나은 이해를 위해 아래 예를 고려하십시오.
예시 1: 함수를 객체로 취급합니다.
파이썬3
# Python program to illustrate functions> # can be treated as objects> def> shout(text):> > return> text.upper()> print> (shout(> 'Hello'> ))> yell> => shout> print> (yell(> 'Hello'> ))> |
산출:
HELLO HELLO
위의 예에서는shout 함수를 변수에 할당했습니다. 이것은 함수를 호출하지 않고 대신 외침에 의해 참조되는 함수 개체를 가져와 이를 가리키는 두 번째 이름인 소리를 만듭니다.
예 2: 함수를 인수로 전달하기
파이썬3
# Python program to illustrate functions> # can be passed as arguments to other functions> def> shout(text):> > return> text.upper()> def> whisper(text):> > return> text.lower()> def> greet(func):> > # storing the function in a variable> > greeting> => func(> '''Hi, I am created by a function passed as an argument.'''> )> > print> (greeting)> greet(shout)> greet(whisper)> |
산출:
HI, I AM CREATED BY A FUNCTION PASSED AS AN ARGUMENT. hi, i am created by a function passed as an argument.
위의 예에서 Greeting 함수는 또 다른 함수를 매개변수로 사용합니다(이 경우에는 소리치기와 속삭임). 인수로 전달된 함수는 Greeting 함수 내에서 호출됩니다.
예시 3: 다른 함수에서 함수를 반환합니다.
파이썬3
# Python program to illustrate functions> # Functions can return another function> def> create_adder(x):> > def> adder(y):> > return> x> +> y> > return> adder> add_15> => create_adder(> 15> )> print> (add_15(> 10> ))> |
산출:
25
위의 예에서는 다른 함수 내부에 함수를 생성한 다음 내부에서 생성된 함수를 반환했습니다.
위의 세 가지 예는 데코레이터를 이해하는 데 필요한 중요한 개념을 설명합니다. 이를 살펴본 후 이제 데코레이터에 대해 자세히 살펴보겠습니다.
데코레이터
위에서 언급했듯이 데코레이터는 함수나 클래스의 동작을 수정하는 데 사용됩니다. 데코레이터에서 함수는 다른 함수의 인수로 사용된 다음 래퍼 함수 내에서 호출됩니다.
데코레이터 구문:
@gfg_decorator def hello_decorator(): print('Gfg') '''Above code is equivalent to - def hello_decorator(): print('Gfg') hello_decorator = gfg_decorator(hello_decorator)''' 위의 코드에서 gfg_ decorator는 호출 가능한 함수로, 다른 호출 가능한 함수인 hello_decorator 함수 위에 일부 코드를 추가하고 래퍼 함수를 반환합니다.
데코레이터는 행동 :
파이썬3
# defining a decorator> def> hello_decorator(func):> > # inner1 is a Wrapper function in> > # which the argument is called> > > # inner function can access the outer local> > # functions like in this case 'func'> > def> inner1():> > print> (> 'Hello, this is before function execution'> )> > # calling the actual function now> > # inside the wrapper function.> > func()> > print> (> 'This is after function execution'> )> > > return> inner1> # defining a function, to be called inside wrapper> def> function_to_be_used():> > print> (> 'This is inside the function !!'> )> # passing 'function_to_be_used' inside the> # decorator to control its behaviour> function_to_be_used> => hello_decorator(function_to_be_used)> # calling the function> function_to_be_used()> |
산출:
Hello, this is before function execution This is inside the function !! This is after function execution
위 코드의 동작과 function_to_be_used가 호출될 때 단계별로 어떻게 실행되는지 살펴보겠습니다.
쉽게 알 수 있는 또 다른 예로 넘어가겠습니다. 함수의 실행 시간 데코레이터를 사용합니다.
파이썬3
# importing libraries> import> time> import> math> # decorator to calculate duration> # taken by any function.> def> calculate_time(func):> > > # added arguments inside the inner1,> > # if function takes any arguments,> > # can be added like this.> > def> inner1(> *> args,> *> *> kwargs):> > # storing time before function execution> > begin> => time.time()> > > func(> *> args,> *> *> kwargs)> > # storing time after function execution> > end> => time.time()> > print> (> 'Total time taken in : '> , func.__name__, end> -> begin)> > return> inner1> # this can be added to any function present,> # in this case to calculate a factorial> @calculate_time> def> factorial(num):> > # sleep 2 seconds because it takes very less time> > # so that you can see the actual difference> > time.sleep(> 2> )> > print> (math.factorial(num))> # calling the function.> factorial(> 10> )> |
산출:
3628800 Total time taken in : factorial 2.0061802864074707
함수가 무언가를 반환하거나 인수가 함수에 전달되면 어떻게 되나요?
위의 모든 예에서 함수는 아무것도 반환하지 않았으므로 문제가 없었지만 반환된 값이 필요할 수 있습니다.
파이썬3
def> hello_decorator(func):> > def> inner1(> *> args,> *> *> kwargs):> > > print> (> 'before Execution'> )> > > # getting the returned value> > returned_value> => func(> *> args,> *> *> kwargs)> > print> (> 'after Execution'> )> > > # returning the value to the original frame> > return> returned_value> > > return> inner1> # adding decorator to the function> @hello_decorator> def> sum_two_numbers(a, b):> > print> (> 'Inside the function'> )> > return> a> +> b> a, b> => 1> ,> 2> # getting the value through return of the function> print> (> 'Sum ='> , sum_two_numbers(a, b))> |
산출:
before Execution Inside the function after Execution Sum = 3
위의 예에서 내부 함수의 매개변수에 큰 차이가 있음을 알 수 있습니다. 내부 함수는 인수를 *args 및 **kwargs로 사용합니다. 이는 위치 인수 튜플이나 키워드 인수 사전이 어떤 길이로도 전달될 수 있음을 의미합니다. 이는 임의 개수의 인수를 갖는 함수를 장식할 수 있는 일반 장식자가 됩니다.
체인 데코레이터
간단히 말해서 데코레이터를 연결한다는 것은 여러 데코레이터로 함수를 꾸미는 것을 의미합니다.
예:
파이썬3
# code for testing decorator chaining> def> decor1(func):> > def> inner():> > x> => func()> > return> x> *> x> > return> inner> def> decor(func):> > def> inner():> > x> => func()> > return> 2> *> x> > return> inner> @decor1> @decor> def> num():> > return> 10> @decor> @decor1> def> num2():> > return> 10> > print> (num())> print> (num2())> |
산출:
400 200
위의 예는 다음과 같이 함수를 호출하는 것과 유사합니다.
decor1(decor(num)) decor(decor1(num2))