히스토리 메타클래스는 클래스의 모든 메서드 호출과 속성 변경을 추적하여 히스토리를 기록하는 데 사용할 수 있습니다. 아래는 히스토리 기록을 위해 메타클래스를 사용하는 샘플 코드입니다.
히스토리 메타클래스 코드
from datetime import datetime
from functools import wraps
class HistoryMeta(type):
"""히스토리를 기록하는 메타클래스"""
def __new__(cls, name, bases, dct):
# 히스토리 저장용 리스트 추가
dct.setdefault('__history__', [])
# 기존 메서드 래핑
for attr_name, attr_value in dct.items():
if callable(attr_value) and not attr_name.startswith("__"):
dct[attr_name] = cls.wrap_method(attr_name, attr_value)
# 속성 설정 감시
dct['__setattr__'] = cls.wrap_setattr(dct.get('__setattr__', object.__setattr__))
return super().__new__(cls, name, bases, dct)
@staticmethod
def wrap_method(method_name, method):
"""메서드를 래핑하여 호출 기록 추가"""
@wraps(method)
def wrapped_method(self, *args, **kwargs):
# 히스토리 추가
entry = {
"timestamp": datetime.now(),
"action": "method_call",
"method": method_name,
"args": args,
"kwargs": kwargs,
}
self.__history__.append(entry)
return method(self, *args, **kwargs)
return wrapped_method
@staticmethod
def wrap_setattr(original_setattr):
"""속성 설정을 래핑하여 변경 기록 추가"""
def wrapped_setattr(self, key, value):
if not key.startswith("__history__") and hasattr(self, '__history__'):
entry = {
"timestamp": datetime.now(),
"action": "attribute_change",
"attribute": key,
"new_value": value,
}
self.__history__.append(entry)
original_setattr(self, key, value)
return wrapped_setattr
def get_history(cls):
"""클래스의 히스토리 반환"""
return cls.__dict__.get('__history__', [])
class HistoryEnabledClass(metaclass=HistoryMeta):
"""히스토리 메타클래스를 사용하는 클래스"""
def __init__(self, name):
self.name = name
def update_name(self, new_name):
self.name = new_name
def display_name(self):
print(f"Name: {self.name}")
# 사용 예제
if __name__ == "__main__":
obj = HistoryEnabledClass("Initial Name")
obj.display_name()
obj.update_name("Updated Name")
obj.display_name()
# 속성 직접 변경
obj.name = "Directly Updated Name"
# 히스토리 출력
print("\nHistory:")
for entry in obj.__history__:
print(entry)
코드 설명
- HistoryMeta 메타클래스:
- __new__: 클래스의 모든 메서드와 속성 설정 메서드를 래핑하여 히스토리를 기록할 수 있도록 수정.
- wrap_method: 메서드를 래핑하여 호출 시 호출 정보(메서드 이름, 인수 등)를 히스토리에 기록.
- wrap_setattr: 속성 설정을 감지하여 속성 변경 정보를 히스토리에 기록.
- HistoryEnabledClass:
- HistoryMeta 메타클래스를 사용하는 클래스.
- 메서드 호출 및 속성 변경이 자동으로 기록됨.
- 사용 예제:
- display_name 및 update_name 메서드를 호출하고 속성을 직접 수정한 뒤, 히스토리를 출력.
실행 결과 (예시):
Name: Initial Name
Name: Updated Name
History:
{'timestamp': datetime.datetime(2025, 1, 7, 12, 0, 0, 123456), 'action': 'method_call', 'method': 'display_name', 'args': (), 'kwargs': {}}
{'timestamp': datetime.datetime(2025, 1, 7, 12, 0, 1, 123456), 'action': 'method_call', 'method': 'update_name', 'args': ('Updated Name',), 'kwargs': {}}
{'timestamp': datetime.datetime(2025, 1, 7, 12, 0, 2, 123456), 'action': 'method_call', 'method': 'display_name', 'args': (), 'kwargs': {}}
{'timestamp': datetime.datetime(2025, 1, 7, 12, 0, 3, 123456), 'action': 'attribute_change', 'attribute': 'name', 'new_value': 'Directly Updated Name'}
주요 기능
- 메서드 호출 기록: 메서드 이름, 인수, 호출 시간 등을 기록.
- 속성 변경 기록: 변경된 속성 이름, 새 값, 변경 시간 등을 기록.
- 중앙화된 히스토리 관리: 클래스 수준에서 모든 변경 사항을 추적 가능.
이 코드는 디버깅, 로깅, 변경 추적 등을 자동화하는 데 유용하며, 클래스의 동작 이력을 투명하게 관리할 수 있습니다.
'데이터 카드 자료구조' 카테고리의 다른 글
[데이터 카드 자료구조] 푸터 카드를 생성하기 위한 메타클래스 (0) | 2025.01.07 |
---|---|
[데이터 카드 자료구조] 헤더 카드를 생성하기 위한 메타클래스 (0) | 2025.01.07 |
[데이터 카드 자료구조] 히스토리 보조 카드 샘플 코드 (0) | 2025.01.07 |
[데이터 카드 자료구조] 데이터카드 콘테이터 클래스 샘플 코드 (0) | 2025.01.07 |
[데이터 카드 자료구조] 메타정보를 표현하는 샘플 코드 (0) | 2025.01.07 |