Python 내부: 데코레이터
Source: Dev.to
Introduction
추상화 레이어를 허물고 힙 할당, 클로저, 시간 복잡성을 가이드로 삼아 처음부터 데코레이터를 만들어 보겠습니다.
C++이나 Java 같은 정적·컴파일 언어 배경을 가지고 있다면 파이썬 데코레이터는 마법처럼 느껴질 수 있습니다. @login_required 를 함수 위에 붙이면 갑자기 인증 로직이 들어가고, @app.route("/") 를 붙이면 웹 엔드포인트가 됩니다.
복잡함을 숨기기 때문에 마법처럼 보이지만, 엔지니어라면 마법 은 아직 이해하지 못한 코드일 뿐이라는 것을 압니다.
이번 포스트에서는 파이썬 메타프로그래밍을 풀어보겠습니다. 데코레이터를 어떻게 쓰는지만 배우는 것이 아니라, 이를 가능하게 하는 메모리 메커니즘을 이해하고, 프로덕션 수준의 유틸리티 벨트를 만들며, 함수의 알고리즘 복잡성을 근본적으로 바꾸는 방법까지 다룹니다.
Part 1: The Mechanics (No Magic Allowed)
데코레이터를 작성하기 전에 원재료를 이해해야 합니다. 파이썬에서 데코레이터를 가능하게 하는 메커니즘은 일급 함수와 클로저입니다.
1. Functions are just heap‑allocated objects
- C에서는 함수가
.text섹션에 있는 명령어 블록입니다. - 파이썬에서는 함수가 힙에 존재하는 완전한 객체(
PyObject구조체)입니다.
객체이기 때문에 다음이 가능합니다:
- 변수를 할당한다,
- 다른 함수의 인자로 전달한다,
- 다른 함수에서 반환한다.
함수를 데이터처럼 다루는 이 능력이 메타프로그래밍의 초석입니다.
2. The Engine: Closures
C++ 배경이라면 지역 변수는 함수의 스택 프레임이 사라지면 사라진다는 것을 알 것입니다. 파이썬은 다릅니다. 내부 함수가 외부 스코프의 변수를 참조하면 파이썬 컴파일러가 이를 감지하고 그 변수를 스택 아이템에서 힙에 있는 셀 객체로 승격합니다.
외부 함수가 반환된 뒤에도 내부 함수는 그 셀 객체에 대한 참조를 유지합니다. 이 “기억된 환경”을 클로저라고 합니다.
클로저는 외부 함수가 실행을 마친 후에도 자신을 둘러싼 스코프의 변수를 기억하는 함수입니다.
데코레이터는 자신이 감싸는 어떤 함수를 기억하기 위해 전적으로 클로저에 의존합니다.
Part 2: Building the Pattern
데코레이터는 근본적으로 간단합니다: 함수를 입력으로 받아 새로운 함수를 반환하는 함수입니다.
Manual decoration (the raw pattern)
# The decorator factory
def my_decorator(target_func):
# The wrapper closure retains access to 'target_func'
def wrapper():
print(">>> Before execution")
target_func() # Calling the original function
print(">> Before execution
Executing core logic…
Note: In production, prefer Python’s built‑in functools.lru_cache over rolling your own, as it handles cache bounding to prevent memory leaks.
Summary
데코레이터는 마법이 아닙니다. 일급 함수와 클로저를 우아하게 적용한 결과물입니다. 파이썬이 스코프와 객체 수명 주기를 힙에서 어떻게 다루는지 이해하면, 동작을 수정하고 로직을 주입하며 성능을 깔끔하고 명시적으로 최적화할 수 있는 힘을 얻게 됩니다.