[python] decorator

단간단간·2024년 4월 25일
post-thumbnail

데코레이터

데코레이터란?

  • 함수를 수정하지 않고 그 기능을 확장하거나 변경할 수 있도록 해주는 유용한 도구
  • 기본적으로는 다른 함수를 입력 받고, 그 함수를 이용한 새로운 함수를 반환하는 함수이다.
  • 공통으로 사용되는 로직이 많고, 일부분만 갈아끼워주는 형태로 사용할 경우 코드의 중복성을 줄일 수 있는데 이런 경우 데코레이터를 많이 사용하는 것 같다.

데코레이터 구조

  • 외부 함수: 이 함수가 데코레이터 역할을 하며, 내부 함수를 반환한다.
  • 내부 함수: 이 함수가 실제로 입력 함수를 수정하는 로직을 포함한다.
  • @데코레이터 사용: 어떤 함수에 데코레이터를 적용할 때는 함수 정의 위에 @ 기호를 사용한다.

예시

def test_decorator_1(func):
    def wrapper():
        print("test_decorator_1 실행 중")
        func()
        print("test_decorator_1 실행 완료")

    return wrapper


@test_decorator_1
def say_hello():
    print("Hello!")


say_hello()
test_decorator_1 실행 중
Hello!
test_decorator_1 실행 완료
  • say_hello -> test_decorator_1(func) -> wrapper
  • say_hello() -> test_decorator_1(func)() -> wrapper()
  • 대략 이런 느낌인 것 같다. 즉, 데코레이터로 감싸여진 함수 == wrapper 라고 이해하면 될 것 같다. say_hello()를 호출하면 wrapper()함수가 호출되는 느낌.

참고

파이썬에서 함수를 호출할 때 괄호 () 없이 함수 이름만 반환하는 경우, 실제로 함수가 실행되지 않고 함수 객체 자체가 반환된다.

이렇게 반환된 함수 객체는 다른 변수에 할당되거나, 다른 함수의 인자로 전달될 수 있으며, 필요한 시점에 나중에 호출할 수 있다.


다중 데코레이터 적용

  • 함수 정의에 가장 가까운 것부터 시작하여 바깥쪽으로 순서대로 적용
  • 각 데코레이터가 이전 데코레이터가 반환한 함수(wrapper)를 자신의 입력으로 받아 처리
  • 이러한 과정을 통해 각기 다른 기능들을 함수에 계층적으로 추가 가능

예제

def test_decorator_2(func):
    def wrapper(*args, **kwargs):
        print("test_decorator_2 실행 중")
        func(*args, **kwargs)
        print("test_decorator_2 실행 완료")

    return wrapper


def test_decorator_1(func):
    def wrapper(*args, **kwargs):
        print("test_decorator_1 실행 중")
        func(*args, **kwargs)
        print("test_decorator_1 실행 완료")

    return wrapper


@test_decorator_1
@test_decorator_2
def say_hello():
    print("say_hello 함수 실행!")
test_decorator_1 실행 중
test_decorator_2 실행 중
say_hello 함수 실행!
test_decorator_2 실행 완료
test_decorator_1 실행 완료
  • test_decorator_2 -> test_decorator_1 순서로 호출
  • test_decorator_1이 test_decorator_2의 wrapper함수를 받아서 실행
    • print("test_decorator_1 실행 중") 실행

    • func(*args, **kwargs) 실행 -> 이는 test_decorator_2의 wrapper함수 이므로

      • print("test_decorator_2 실행 중") 실행
      • func(*args, **kwargs) 실행 -> say_hello() 실행
      • print("test_decorator_2 실행 완료") 실행
    • print("test_decorator_1 실행 완료") 실행

  • 대략 위의 과정을 따르는 것 같다. 호출은 데코레이터 아래서부터 위로, 실행되는건 위에서부터 아래로 이런 느낌인데 맞는지 잘 모르겠다.
profile
simple is best

0개의 댓글