Computer >> 컴퓨터 >  >> 프로그래밍 >> Python

파이썬 함수 데코레이터 완벽 정리: 개념과 동작 원리

파이썬에서 데코레이터(Decorator)는 함수, 메서드, 클래스처럼 호출 가능한(callable) 객체의 동작을 원본 코드를 영구적으로 수정하지 않고도 확장하거나 변경할 수 있게 해주는 강력한 도구입니다. 쉽게 말해, 데코레이터는 다른 함수나 클래스를 수정하기 위해 사용되는 호출 가능한 객체라고 할 수 있습니다.

함수 데코레이터는 하나의 함수 참조를 인자로 받아 그 함수 주위에 래퍼(wrapper)를 감싸고, 래퍼가 적용된 새로운 함수를 반환하는 함수입니다.

데코레이터의 기본 구조

다음 예제를 통해 함수 데코레이터의 동작 방식을 이해해 보겠습니다.

코드 1

@decorator
def func(arg):
    return "value"

위 코드는 사실 아래 코드와 완전히 동일하게 동작합니다.

코드 2

def func(arg):
    return "value"
func = decorator(func)

즉, 데코레이터는 단순히 함수를 인자로 받아 새로운 함수를 반환하는 또 다른 함수일 뿐입니다.

래퍼 함수로 실행 흐름 제어하기

데코레이터는 본질적으로 다른 함수를 "장식(decorate)"하거나 "감싸(wrap)"며, 감싸진 함수가 실행되기 전과 후에 추가 코드를 실행할 수 있도록 해줍니다. 아래 예제를 살펴보겠습니다.

def our_decorator(func):
    def function_wrapper(x):
        print("Before calling " + func.__name__)
        func(x)
        print("After calling " + func.__name__)
    return function_wrapper

def foo(x):
    print("Hi, foo has been called with " + str(x))

print("We call foo before decoration:")
foo("Hi")

print("We now decorate foo with f:")
foo = our_decorator(foo)

print("We call foo after decoration:")
foo(90)

출력 결과

We call foo before decoration:
Hi, foo has been called with Hi
We now decorate foo with f:
We call foo after decoration:
Before calling foo
Hi, foo has been called with 90
After calling foo

출력 결과에서 확인할 수 있듯이, 데코레이션이 적용된 후에는 foo 함수가 호출될 때마다 원래 함수의 로직 앞뒤로 Before callingAfter calling 메시지가 함께 출력됩니다. 이것이 바로 데코레이터가 기존 함수의 핵심 로직은 그대로 유지하면서 부가적인 기능을 덧붙이는 방식입니다.

가장 단순한 형태의 데코레이터

위 예제가 다소 복잡하게 느껴진다면, 가장 단순한 형태의 데코레이터를 먼저 살펴보겠습니다.

def null_decorator(func):
    return func

null_decorator는 호출 가능한 객체(함수)이며, 다른 호출 가능한 객체를 입력으로 받아 아무 수정 없이 그대로 반환합니다. 이름 그대로 "아무것도 하지 않는" 데코레이터입니다.

null_decorator로 함수 장식하기

이제 위에서 만든 가장 단순한 데코레이터를 활용해 다른 함수를 장식(감싸)해 보겠습니다.

def null_decorator(func):
    return func

def greet():
    return "Hello, Python!"

greet = null_decorator(greet)
>>> greet()
'Hello, Python!'

위 코드에서는 greet 함수를 정의한 직후, 이를 null_decorator 함수에 통과시켜 즉시 데코레이션했습니다.

@ 문법으로 더 간결하게 작성하기

위 예제처럼 null_decorator를 명시적으로 호출한 뒤 greet 변수에 다시 할당하는 대신, 파이썬에서 제공하는 @ 문법(@syntax)을 사용하면 한 번의 과정으로 함수를 데코레이션할 수 있습니다. 훨씬 간결하고 가독성이 좋은 방식입니다.

@null_decorator
def greet():
    return "Hello, Python!"
>>> greet()
'Hello, Python!'

@ 기호를 함수 정의 바로 위에 붙여주기만 하면, 파이썬 인터프리터가 자동으로 해당 함수를 데코레이터에 전달하고 그 결과를 원래 함수 이름에 재할당합니다. 이처럼 데코레이터는 로깅, 성능 측정, 접근 권한 검사 등 다양한 상황에서 코드 중복 없이 깔끔하게 기능을 확장할 수 있는 필수적인 파이썬 문법입니다.