youngfromnowhere

[Python] Decorator 본문

Python

[Python] Decorator

곽일땡 2022. 11. 7. 21:47

Python flask를 배우다보니 반가운 구문을 만나게 되었다.

바로 '@'을 쓰는 python decorator다.

 

예전에 python의 property 기능에 대해 파다가 만난 개념이다. 오늘 여기에 다시정리해본다.

 

https://docs.python.org/3/glossary.html#term-decorator

 

Glossary — Python 3.11.0 documentation

An extension of the familiar real number system in which all numbers are expressed as a sum of a real part and an imaginary part. Imaginary numbers are real multiples of the imaginary unit (the square root of -1), often written i in mathematics or j in eng

docs.python.org


다음과 같이 function deco가 정의되어 있다고 하자.

#code block 01
def deco(arg):
	... body ...
    return some_obj

이 때 다음 두 code는 서로 equivalent 하다.

#code block 02
@deco
def main(arg):
	... body ...
    return some_obj
#code block 03
def main(arg):
	... body ...
    return some_obj

main = deco(main)

 

위에 정의된 deco에 function object를 입력하면 deco는 function object를 return한다. 이것을 반복적으로 함수들의 정의를 조작하는데 쓸 수 있다. 다만 대상 함수의 body 중간에 code를 끼워놓을 수는 없다. 대상 함수의 body 앞 뒤에 code를 추가하기 쉽도록 만든 기능이기에 decorator라 칭하는 것이다.

 

예시.

#code block 04
def deco(funcobj):
    def wrapper(arg):
        print("this string is added by decorator")
        funcobj(arg)
        print("this string is added by decorator")
    return wrapper

@deco
def main(arg):
    print(f"main(arg={arg}) has been called")


if __name__ == '__main__':
    main(3)
    main(4)
    main(5)

code block 04의 실행결과는 다음과 같다.

this string is added by decorator
main(arg=3) has been called
this string is added by decorator
this string is added by decorator
main(arg=4) has been called
this string is added by decorator
this string is added by decorator
main(arg=5) has been called
this string is added by decorator

 

다음과 같이 class 형식으로 decorator를 정의할 수도 있다.

 

#code block 05
class DecoClass:
    def __init__(self, funcobj):
        self.f = funcobj
    def __call__(self, arg):
        print(f"{self.f.__name__} is decorated by DecoClass")
        self.f(arg)
        print(f"{self.f.__name__} is decorated by DecoClass")

@DecoClass
def main(arg):
    print(f"main(arg={arg}) has been called")


if __name__ == '__main__' :
    main(1)
    main(3)
    main(7)

@DecoClass 밑에 main이 정의된 것은 main = DecoClass(main) 과 같은 코드이므로
__init__의 funcobj 인자로 main이 전달되어 DecoClass의 instance가 생성되고 여기에 main이라는 이름이 다시 assign 된다.

이후 main(3)과 같이 호출하면 이는 main.__call__(3)과 equivalent 하므로 __call__의 body가 실행된다. code block 05의 실행결과는 다음과 같다.

main is decorated by DecoClass
main(arg=1) has been called
main is decorated by DecoClass
main is decorated by DecoClass
main(arg=3) has been called
main is decorated by DecoClass
main is decorated by DecoClass
main(arg=7) has been called
main is decorated by DecoClass

main(1), main(3), main(7)의 실행 전후에 DecoClass에 의한 동작이 실행됨을 알 수 있다.

'Python' 카테고리의 다른 글

[Python] python의 special methods  (0) 2022.11.17
[Python] Decorator3. Property  (0) 2022.11.16
[Python] Decorator 2. abstractmethod()  (0) 2022.11.15
[Python] 가상환경  (0) 2022.11.03
[Python] Python의 Method Call  (0) 2022.10.31