반응형
📌 [Python] 데코레이터의 종류와 특징, 사용 방법 정리
📝 소개
Python의 **데코레이터(Decorator)**는 함수 또는 클래스를 수정하지 않고 추가적인 기능을 부여하는 강력한 도구입니다.
쉽게 말해, 기존 코드를 변경하지 않고 기능을 확장할 수 있도록 도와주는 것입니다.
이번 글에서는 데코레이터의 개념, 종류, 사용법을 초보자도 이해할 수 있도록 쉽게 정리하겠습니다.
또한, 실제 프로젝트에서 활용할 수 있는 예제 코드를 함께 제공하겠습니다.
🔍 데코레이터(Decorator)란?
✅ 데코레이터의 정의
- 데코레이터는 기존 함수나 클래스를 감싸서 새로운 기능을 추가하는 Python 기능
- @데코레이터_이름 형태로 사용
- 코드 수정 없이 기능 확장 가능
✅ 데코레이터의 특징
- 함수를 인자로 받아 실행
- 데코레이터는 다른 함수를 감싸는 함수입니다.
- 원래 함수의 기능을 변경하지 않고 확장 가능
- 함수 코드 수정 없이 로깅, 권한 체크, 실행 시간 측정 등의 기능 추가 가능
- 가독성 향상
- 코드가 깔끔해지고 중복을 줄일 수 있음
📌 데코레이터 기본 구조
def my_decorator(func):
def wrapper():
print("Before function execution")
func() # 원래 함수 실행
print("After function execution")
return wrapper # 감싸진 함수 반환
@my_decorator # 데코레이터 적용
def hello():
print("Hello, World!")
hello()
🔹 실행 결과
Before function execution
Hello, World!
After function execution
위 코드에서 @my_decorator를 사용하면 hello() 함수가 my_decorator의 wrapper 함수 안에서 실행됩니다.
반응형
🎯 데코레이터의 종류와 특징
Python에서 사용되는 대표적인 데코레이터의 종류를 정리하면 다음과 같습니다.
종류 | 설명 | 사용 예제 |
기본 함수 데코레이터 | 가장 기본적인 형태의 데코레이터 | @my_decorator |
인자를 받는 데코레이터 | 데코레이터에 추가적인 설정 값을 전달 | @log("DEBUG") |
functools.wraps 적용 데코레이터 | 원본 함수의 __name__과 __doc__을 유지 | @functools.wraps(func) |
클래스 데코레이터 | 클래스를 감싸는 데코레이터 | @my_class_decorator |
메서드 데코레이터 (@staticmethod, @classmethod) | 클래스 내부 메서드에 사용되는 데코레이터 | @staticmethod, @classmethod |
내장 데코레이터 (@property) | 클래스 속성을 메서드처럼 사용 가능 | @property |
PySide6의 @Slot 데코레이터 | Signal과 연결되는 메서드를 최적화 | @Slot() |
📌 다양한 데코레이터 예제
✅ 1. 기본 함수 데코레이터
def simple_decorator(func):
def wrapper():
print("Function is about to execute")
func()
print("Function execution completed")
return wrapper
@simple_decorator
def say_hello():
print("Hello!")
say_hello()
✅ 2. 인자를 받는 데코레이터
def repeat(n):
def decorator(func):
def wrapper(*args, **kwargs):
for _ in range(n):
func(*args, **kwargs)
return wrapper
return decorator
@repeat(3)
def greet():
print("Hello!")
greet()
✅ 3. functools.wraps를 활용한 데코레이터
import functools
def log_function(func):
@functools.wraps(func) # 원본 함수 정보 유지
def wrapper(*args, **kwargs):
print(f"Executing {func.__name__} function")
return func(*args, **kwargs)
return wrapper
@log_function
def add(a, b):
"""두 수를 더하는 함수"""
return a + b
print(add(2, 3))
print(add.__name__) # 원본 함수 이름 유지
🔹 functools.wraps(func)를 사용하면 함수 이름(__name__)과 설명(__doc__)이 유지됩니다.
✅ 4. 클래스 데코레이터
class UpperCaseDecorator:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
result = self.func(*args, **kwargs)
return result.upper()
@UpperCaseDecorator
def get_text():
return "hello, world!"
print(get_text()) # "HELLO, WORLD!"
🔹 클래스를 활용한 데코레이터는 __call__ 메서드를 사용하여 함수처럼 동작할 수 있습니다.
✅ 5. @staticmethod, @classmethod 사용 예제
class Math:
@staticmethod
def add(x, y):
return x + y
@classmethod
def multiply(cls, x, y):
return x * y
print(Math.add(2, 3)) # 5
print(Math.multiply(2, 3)) # 6
✅ 6. @property 사용 예제
class Person:
def __init__(self, name):
self._name = name
@property
def name(self):
return self._name
person = Person("Alice")
print(person.name) # "Alice"
🔹 @property를 사용하면 메서드를 속성처럼 사용할 수 있습니다.
📌 PySide6에서 @Slot 데코레이터 사용하기
✅ @Slot 데코레이터를 사용하는 이유
PySide6에서 @Slot 데코레이터를 사용하면 다음과 같은 장점이 있습니다.
- Signal과 연결될 메서드를 명확히 표시
- 성능 최적화
- C++에서 직접 호출할 수 있도록 최적화됨
- 타입 안정성 제공
- 인자의 타입을 명시할 수 있어 오류 방지 가능
✅ @Slot 사용 예제
from PySide6.QtWidgets import QApplication, QWidget, QPushButton, QLabel, QVBoxLayout
from PySide6.QtCore import Signal, Slot
class MyWindow(QWidget):
button_clicked = Signal() # 버튼 클릭을 위한 Signal 정의
def __init__(self):
super().__init__()
self.setWindowTitle("Signal & Slot Example")
self.resize(300, 200)
# UI 요소 생성
self.label = QLabel("Press the button!")
self.button = QPushButton("Click Me")
self.button.clicked.connect(self.emit_signal)
# Signal-Slot 연결
self.button_clicked.connect(self.update_label)
# 레이아웃 설정
layout = QVBoxLayout()
layout.addWidget(self.label)
layout.addWidget(self.button)
self.setLayout(layout)
def emit_signal(self):
"""Signal을 발생시키는 메서드"""
self.button_clicked.emit()
@Slot() # Slot 데코레이터 사용
def update_label(self):
"""Label의 텍스트를 변경하는 Slot 메서드"""
self.label.setText("Button Clicked!")
# 앱 실행
if __name__ == "__main__":
app = QApplication([])
window = MyWindow()
window.show()
app.exec()
🔹 실행 결과
- 초기 상태: "Press the button!"
- 버튼 클릭 → Signal 발생 → Slot 실행
- 텍스트 변경: "Button Clicked!"
🎯 @Slot을 사용한 경우 vs 사용하지 않은 경우
PySide6에서 @Slot 데코레이터는 선택적으로 사용할 수 있습니다.
하지만, 데코레이터를 사용하면 최적화된 호출 경로를 제공하고, 데이터 타입을 강제할 수 있다는 장점이 있습니다.
🔹 @Slot을 사용한 경우
from PySide6.QtCore import Slot
class Example:
@Slot() # Slot 데코레이터 적용
def my_slot(self):
print("Slot is called!")
🔹 @Slot을 사용하지 않은 경우
class Example:
def my_slot(self):
print("Slot is called!")
✅ 차이점 정리
특성 | Slot 데코레이터 사용 | Slot 데코레이터 미사용 |
명시적 등록 | Slot임을 명확히 선언 | 일반적인 Python 함수 |
성능 최적화 | Qt 내부적으로 최적화됨 | Python 함수로 실행됨 |
타입 안정성 | 데이터 타입을 명시할 수 있음 | 타입 안정성이 없음 |
유지보수성 | Signal-Slot 메커니즘을 명확히 표현 | Slot 여부가 코드에서 명확하지 않음 |
🚀 정리
- 데코레이터는 함수 또는 클래스를 감싸서 기능을 추가하는 강력한 도구
- 기본적인 함수 데코레이터부터 클래스, 메서드, 내장 데코레이터까지 다양하게 활용 가능
- functools.wraps를 활용하면 원본 함수의 정보를 유지할 수 있음
- 클래스 기반 데코레이터를 활용하면 더 확장성이 높아짐
반응형
'코딩취미 > Python' 카테고리의 다른 글
PySide6 QScrollArea에서 스크롤바 제어하기 (0) | 2025.02.26 |
---|---|
Python 딕셔너리 다루기: 키 추가, 검색, 삭제, 병합 방법 (0) | 2025.02.25 |
[Python & PySide6] Slot을 사용하는 이유와 Slot 데코레이터의 차이점 (0) | 2025.02.25 |
파이썬에서 지정된 자리수로 숫자 표시하기 (0) | 2025.02.24 |
PyQt6에서 QScrollArea 사용법: QWidget에 ScrollArea 설정하고 그룹박스 활용하기 (0) | 2025.02.24 |