해당 포스트는 인프런 강의 "타입 파이썬! 올바른 class 사용법과 객체지향 프로그래밍"을 기반으로 작성하였습니다.
타입 파이썬! 올바른 class 사용법과 객체지향 프로그래밍| 윤상석 - 인프런 강의
현재 평점 4.8점 수강생 1,026명인 강의를 만나보세요. Python으로 생산성있는 개발만 아니라 견고하고 안전하게, 그리고 확장성있는 개발을 하세요! 🔥 객체지향 프로그래밍의 원칙, 객체지향 프
www.inflearn.com
1. 배경: 왜 데코레이터가 필요할까?
프로그래밍을 하다 보면 동일한 부가 기능을 여러 함수에서 반복해야 하는 상황이 생깁니다.
예를 들어, 이모티콘을 출력하는 서비스에서 발주사가 “모든 이모티콘에 저작권 문구를 출력해 달라”라고 요청한다고 합시다.
- 처음에는 단순히
print("🙃"),print("🤯"),print("🥰")같은 함수만 있었습니다. - 그런데 저작권 문구를 붙이려면 30개 함수 모두에 중복 코드를 붙여 넣어야 합니다.
- 유지보수가 어렵고, 문구가 바뀔 때마다 전체를 수정해야 하므로 비효율적입니다.
이 문제를 해결하기 위해 데코레이터(decorator) 가 등장합니다.
2. 리팩터링 이전 코드
2.1 최초 구현
def smile():
print("🙃")
def angry():
print("🤯")
def love():
print("🥰")
smile()
angry()
love()
출력은 간단하지만, 공통 기능(저작권 표시)을 넣으려면 불편합니다.
코드 설명
- def로 함수 이름을 붙여 동작을 저장해 둡니다.
- smile() 처럼 괄호를 붙여 부르면 실행됩니다.
- 지금은 각 함수가 이모티콘 하나만 출력합니다. 공통 작업을 넣으려면 모든 함수에 일일이 코드를 더해야 합니다.
2.2 안티패턴: 중복된 코드
def smile():
print("@ 저작권 2025 All rights reserved.")
print("🙃")
def angry():
print("@ 저작권 2025 All rights reserved.")
print("🤯")
def love():
print("@ 저작권 2025 All rights reserved.")
print("🥰")
smile()
angry()
love()
- 30개 함수를 모두 수정해야 함
- 유지보수가 매우 힘듦
- 실수로 빠뜨릴 가능성 큼
코드 설명
- 각 함수 첫 줄에 동일한 문구를 넣었습니다.
- 나중에 문구가 바뀌면 모든 함수를 다시 고쳐야 하죠. 빠뜨리거나 오탈자 위험도 큽니다.
- 이런 반복을 없애는 게 데코레이터의 목표입니다.
3. 함수 감싸기(클로저 활용)
데코레이터를 도입하기 전, 먼저 함수를 감싸는 방식으로 공통 로직을 재사용해봅니다.
def copyright(func):
def new_func():
print("@ 저작권 2025 All rights reserved.")
func()
return new_func
def smile():
print("🙃")
def angry():
print("🤯")
def love():
print("🥰")
smile = copyright(smile)
angry = copyright(angry)
love = copyright(love)
smile()
angry()
love()
- copyright는 함수를 받아 새로운 함수(new_func)를 반환
- 새 함수는 저작권 출력 → 원래 함수 실행 순서로 동작
- 다만, smile = copyright(smile) 같은 재할당 코드가 귀찮습니다.
코드 설명
- copyright는 “포장지”입니다. 원래 함수(func)를 받아 포장한 새 함수(new_func)를 돌려줍니다.
- new_func는 먼저 저작권 문구를 찍고, 이어서 원래 함수를 부릅니다.
- 마지막에 smile = copyright(smile)처럼 원래 이름을 포장된 함수로 교체합니다. 이제 smile()을 부르면 포장된 동작이 실행됩니다.
4. 데코레이터 문법(@)
위 과정을 간소화하기 위해 데코레이터 문법(@) 이 제공됩니다.
즉, @copyright는 smile = copyright(smile) 과 동일합니다.
def copyright(func):
def new_func():
print("@ 저작권 2025 All rights reserved.")
func()
return new_func
@copyright
def smile():
print("🙃")
@copyright
def angry():
print("🤯")
@copyright
def love():
print("🥰")
smile()
angry()
love()
실행 순서
smile()호출 →new_func()실행- 저작권 문구 출력
- 원래
smile()실행
코드 설명(쉽게)
@copyright를 함수 정의 바로 위에 붙이면, 파이썬이 자동으로smile = copyright(smile)처럼 처리해 줍니다.- 즉, 포장을 자동으로 해 주는 표기법이라 보면 됩니다.
- 함수가 많아도 각 함수 위에
@…한 줄만 붙이면 끝입니다.
5. 데코레이터 동작 원리
데코레이터는 크게 두 가지 개념을 바탕으로 합니다.
- 일급 객체(First-class function)
- 함수도 값처럼 주고받을 수 있습니다. 그래서 함수에 함수를 넘기고, 함수를 반환할 수 있습니다.
- 함수도 값처럼 주고받을 수 있습니다. 그래서 함수에 함수를 넘기고, 함수를 반환할 수 있습니다.
- 클로저(Closure)
- 안쪽 함수가 바깥 변수(여기선
func)를 기억합니다. - 그래서
new_func안에서func()를 계속 쓸 수 있습니다. - 즉,
@데코레이터는 원래 함수를 “포장한 함수”로 바꿔치기하는 문법입니다.
- 안쪽 함수가 바깥 변수(여기선
6. 자주 쓰는 실전 데코레이터 예시
- 로깅: 함수 실행 시간 기록
- 권한 검사: 로그인 여부 확인
- 캐싱: 동일 입력에 대한 결과 저장
- 예외 처리: 에러 로그 남기고 복구 시도
- 트랜잭션: DB 시작/커밋/롤백 자동 처리
코드 설명(쉽게)
- 위 항목들은 모두 여러 곳에서 공통으로 필요한 작업입니다.
- 데코레이터로 한 곳에 모아 관리하면, 핵심 로직은 더 읽기 쉬워집니다.
7. 테스트하기
pytest 같은 테스트 프레임워크로 데코레이터 동작을 검증할 수 있습니다.
def test_smile(capsys):
smile()
out = capsys.readouterr().out.splitlines()
assert out[0].startswith("@")
assert out[1] == "🙃"
코드 설명(쉽게)
capsys가 화면 출력을 잡아줍니다.- 첫 줄이 저작권 문구인지, 두 번째 줄에 이모티콘이 맞는지 순서까지 확인합니다.
8. 최종 결론
데코레이터는 단순히 “코드 줄이는 트릭”이 아니라,
공통 관심사를 모듈화하고, 코드를 깔끔하게 유지하며, 유지보수 비용을 줄이는 핵심 도구입니다.
작은 예제에서 시작했지만, 실제 서비스에서는 로깅, 보안, 트랜잭션, 캐싱 등 광범위하게 활용됩니다.
즉, 데코레이터를 잘 이해하면 코드 품질과 생산성이 올라갑니다.