ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Python] 데코레이터와 어노테이션 알아보기
    Python/파이썬 기초 2025. 3. 10. 12:51
    반응형

    파이썬 데코레이터와 어노테이션 알아보기


    파이썬(Python)에서 코딩을 하다보면... 특히 객체지향 프로그래밍에 대해 공부할 때, 종종 함수 위에 @decorator 와 같은 표현을 사용하는 것을 볼 수 있습니다. 이건 어노테이션(annotation)이라는 표현 방법으로, 데코레이터(decorator)라고 하는 기능을 함수에 적용하는 문법입니다. 이렇게 설명하면 무슨 말인지 모를테니, 우선은 데코레이터와 어노테이션의 정의부터 알아보고 구현해 보도록 하겠습니다.

     

    데코레이터는 기존에 정의된 함수가 있는 경우, 이를 바꾸지 않고도 새로운 기능을 추가할 수 있게 만드는 함수입니다. 기본이 되는 기능이 하나 있고, 이 기능을 다양한 위치에서 사용하면서 약간의 변경을 가하고 싶을때 유용한 기능입니다. 글로 설명하는 것은 와닿지 않을테니, 자주 사용할법한 예제 몇 가지를 따라해 보도록 하겠습니다.

     

     

    데코레이터가 필요한 이유


    데코레이터를 사용하기 전에, 우선은 기능을 추가할 대상이 되는 함수를 젇의해 보겠습니다. 두 수를 입력받은 뒤, 해당 숫자의 최소공배수를 반환하는 함수를 만들어 보고, 이 함수를 수정하면서 데코레이터가 왜 필요한지 알아보도록 하지요.

     

     

    def lcm(x, y):
        a = max(x, y)
        b = x * y
    
        for res in range(a, b + 1):
            if res % x == 0 and res % y == 0:
                print(f'입력된 값의 최소공배수는 {res} 입니다.')
                break
    
    lcm(15,4)
    입력된 값의 최소공배수는 60 입니다.

     

     

    위와 같이, lcm() 함수를 정의한 뒤 새로운 기능을 추가할 필요가 있다고 가정해 봅시다. 가령, lcm() 함수의 결과물을 출력하기 전에 입력된 x, y값을 출력하도록 수정해 보는거죠. 이 때는 lcm() 함수를 직접 수정하거나, lcm() 함수를 호출하는 새로운 함수를 만들어서 해결하는 것이 일반적입니다.

     

     

    # 수정안 1
    def lcm_modified(x, y):
        print(f'입력된 값은 {x, y} 입니다.')
    
        a = max(x, y)
        b = x * y
    
        for res in range(a, b + 1):
            if res % x == 0 and res % y == 0:
                print(f'입력된 값의 최소공배수는 {res} 입니다.')
                break
    
    lcm_modified(15,4)
    입력된 값은 (15, 4) 입니다.
    입력된 값의 최소공배수는 60 입니다.

     

    # 수정안 2
    def lcm_modified2(x, y):
        print(f'입력된 값은 {x, y} 입니다.')
        lcm(x, y)
    
    lcm_modified2(15,4)
    입력된 값은 (15, 4) 입니다.
    입력된 값의 최소공배수는 60 입니다.

     

     

    그런데, 이렇게 함수를 직접 수정한다면 문제가 발생합니다.

     

    만약 lcm_modified() 와 같은 해결책을 선택한다면, lcm() 함수의 알고리즘이 바뀔 경우 이 함수와 같이 수정한 대상을 일일히 찾아서 함께 수정해야 한다는 단점이 있습니다. 내가 lcm_modified() 처럼 수정한 함수를 잔뜩 만들어 두었다면 유지보수가 사실상 불가능한 수준이 되어버리겠지요.

     

    만약 lcm_modified2() 와 같은 해결책을 선택한다면, lcm_modified() 함수와 같은 문제는 해결할 수 있습니다. lcm() 함수를 수정하면 lcm_modified2() 함수도 함께 수정된 정보가 반영되니까요. 하지만, 내가 lcm() 함수뿐만 아니라, 함께 수정해야 할 lcm2(), lcm3(), lcm4(), ... 함수이 있다면 덩달아서 lcm_modified2_2(), lcm_modified2_3(), lcm_modified2_4(), ... 함수를 만들어야 할겁니다.

     

     

    데코레이터 만들기


    이제는 데코레이터를 이용해서 lcm() 함수를 수정해 보도록 하겠습니다. 데코레이터는 수정안 2와 기본적인 개념이 다르지 않습니다.

     

     

    # 수정안 3
    def print_inputs(func):  # 매개변수 func는 함수입니다
        def wrapper(x, y):
            print(f'입력된 값은 {x, y} 입니다.')
            return func(x, y)
        return wrapper  # 함수를 반환합니다
    
    lcm = print_inputs(lcm)  # 데코레이터 적용
    lcm(15,4)
    입력된 값은 (15, 4) 입니다.
    입력된 값의 최소공배수는 60 입니다.

     

     

    print_inputs() 와 같은 데코레이터를 만들어 둔다면, lcm() 뿐만 아니라 다른 함수에도 두 입력된 값을 출력할 수 있게 됩니다. 이렇게 하면 특정한 기능을 미리 정의해둔 뒤, 해당 기능을 여러 함수에 적용해야 할 때 유용하게 써먹을 수 있지요. 데코레이터를 만들 때는, 아래와 같은 조건에 따라 만들면 됩니다.

     

    • 데코레이터는 매개변수로 함수를 입력받습니다.
    • 데코레이터 안에는 기존 함수를 호출하는 새로운 함수를 정의합니다.
    • 데코레이터의 반환값은 데코레이터 안에 정의된 새로운 함수입니다.

     

    어노테이션 알아보기


    만약 데코레이터를 미리 만들어둔 뒤, 새로 정의하는 함수에 데코레이터를 적용하려면 위와 같은 방법 이외에, @ 표기를 이용해서 추가 정보를 입력할 수 있습니다. 이를 어노테이션이라고 하는데요, 어노테이션은 아래와 같이 함수 정의 바로 위에 작성을 하면 됩니다.

     

     

    @print_inputs  # annotation
    def lcm_annotated(x, y):
        a = max(x, y)
        b = x * y
    
        for res in range(a, b + 1):
            if res % x == 0 and res % y == 0:
                print(f'입력된 값의 최소공배수는 {res} 입니다.')
                break
    
    lcm_annotated(15, 4)
    입력된 값은 (15, 4) 입니다.
    입력된 값의 최소공배수는 60 입니다.
    반응형

    댓글

문의: jwkang3929@naver.com