통계 정보를 포함하는 메타클래스를 만들어 클래스의 사용 현황(예: 인스턴스 생성 횟수, 메서드 호출 횟수 등)을 자동으로 추적하는 샘플 코드를 작성해 보았습니다.

from collections import defaultdict
from functools import wraps

class StatsMeta(type):
    """통계 정보를 포함한 메타클래스"""
    def __new__(cls, name, bases, dct):
        # 통계를 저장할 딕셔너리 추가
        dct.setdefault('__stats__', {
            'instance_count': 0,  # 생성된 인스턴스 수
            'method_calls': defaultdict(int),  # 메서드 호출 횟수
        })
        # 메서드를 래핑하여 호출 횟수 추적
        for key, value in dct.items():
            if callable(value) and not key.startswith("__"):
                dct[key] = cls.wrap_method(value, key)
        return super().__new__(cls, name, bases, dct)

    @staticmethod
    def wrap_method(method, method_name):
        """메서드 호출 횟수를 추적하기 위한 래핑 함수"""
        @wraps(method)
        def wrapped_method(self, *args, **kwargs):
            # 호출 횟수 증가
            self.__class__.__stats__['method_calls'][method_name] += 1
            return method(self, *args, **kwargs)
        return wrapped_method

    def __call__(cls, *args, **kwargs):
        # 인스턴스 생성 횟수 증가
        cls.__stats__['instance_count'] += 1
        return super().__call__(*args, **kwargs)

    def get_stats(cls):
        """현재 클래스의 통계 정보 반환"""
        return cls.__stats__

# 통계 정보를 추적하는 데이터 클래스
class DataClass(metaclass=StatsMeta):
    def method_a(self):
        print("Method A called.")

    def method_b(self):
        print("Method B called.")

# 사용 예제
if __name__ == "__main__":
    # 클래스 인스턴스 생성
    obj1 = DataClass()
    obj2 = DataClass()

    # 메서드 호출
    obj1.method_a()
    obj2.method_a()
    obj1.method_b()

    # 통계 정보 출력
    stats = DataClass.get_stats()
    print(f"Instance Count: {stats['instance_count']}")
    print("Method Calls:")
    for method, count in stats['method_calls'].items():
        print(f"  {method}: {count}")

코드 설명

  1. StatsMeta 메타클래스:
    • __stats__: 클래스 수준에서 통계를 저장하는 딕셔너리를 추가.
    • wrap_method: 클래스의 메서드를 래핑하여 호출 시 통계 정보를 업데이트.
    • __call__: 인스턴스 생성 시 instance_count를 증가.
    • get_stats: 통계 정보를 반환하는 클래스 메서드.
  2. DataClass:
    • StatsMeta 메타클래스를 사용하여 메서드 호출 및 인스턴스 생성 통계를 자동으로 관리.
  3. 사용 예제:
    • DataClass 인스턴스를 생성하고 메서드를 호출한 뒤, 통계 정보를 출력.

실행 결과 (예시):

Method A called.
Method A called.
Method B called.
Instance Count: 2
Method Calls:
  method_a: 2
  method_b: 1

이 메타클래스는 클래스의 동작을 자동으로 감시하고, 개발 및 디버깅 단계에서 클래스의 사용 통계를 확인하는 데 유용합니다.

파이썬에서 메타클래스는 클래스를 생성하는 데 사용되는 "클래스의 클래스"입니다. 메타데이터와 관련된 용도로 메타클래스를 활용하면 클래스 정의 시 자동으로 메타데이터를 추가하거나 검증 로직을 삽입할 수 있습니다.

다음은 메타데이터 관리 목적의 메타클래스 샘플 코드입니다:

# 메타데이터를 자동으로 추가하는 메타클래스
class MetaDataMeta(type):
    def __new__(cls, name, bases, dct):
        # 메타데이터를 클래스에 자동 추가
        dct.setdefault('__metadata__', {})
        dct['__metadata__']['created_at'] = datetime.now()
        dct['__metadata__']['author'] = dct.get('__author__', 'Unknown')
        dct['__metadata__']['version'] = dct.get('__version__', '1.0')
        return super().__new__(cls, name, bases, dct)

    def update_metadata(cls, key, value):
        """메타데이터 업데이트 메서드"""
        if '__metadata__' not in cls.__dict__:
            cls.__metadata__ = {}
        cls.__metadata__[key] = value

# 메타클래스를 사용하는 데이터 클래스
class DataClass(metaclass=MetaDataMeta):
    __author__ = "John Doe"
    __version__ = "2.0"

    def display_metadata(self):
        """현재 클래스의 메타데이터 출력"""
        metadata = getattr(self.__class__, '__metadata__', {})
        print(f"Metadata for {self.__class__.__name__}:")
        for key, value in metadata.items():
            print(f"  {key}: {value}")

# 사용 예제
class MyData(DataClass):
    pass

if __name__ == "__main__":
    # MyData 클래스 생성 시 자동 메타데이터 삽입
    my_data = MyData()
    my_data.display_metadata()

    # 메타데이터 업데이트
    MyData.update_metadata('last_accessed', '2025-01-07')
    my_data.display_metadata()

코드 설명

  1. MetaDataMeta 메타클래스:
    • 클래스 정의 시 __metadata__라는 딕셔너리를 추가하여 기본 메타데이터를 설정.
    • created_at, author, version 같은 기본 메타데이터를 자동으로 삽입.
    • update_metadata 메서드를 통해 동적으로 메타데이터를 업데이트할 수 있음.
  2. DataClass 기반 클래스:
    • 메타클래스로 MetaDataMeta를 사용하여 메타데이터 관리 기능을 상속.
  3. 사용 예제:
    • MyData 클래스를 정의하면 MetaDataMeta가 자동으로 메타데이터를 삽입.
    • update_metadata를 통해 메타데이터를 동적으로 업데이트 가능.

실행 결과 (예시):

Metadata for MyData:
  created_at: 2025-01-07 12:00:00.123456
  author: John Doe
  version: 2.0
Metadata for MyData:
  created_at: 2025-01-07 12:00:00.123456
  author: John Doe
  version: 2.0
  last_accessed: 2025-01-07

이 메타클래스는 클래스 정의 시점에 메타데이터를 관리하고, 클래스의 공통적인 속성을 중앙에서 통제하기 위한 구조를 제공합니다.

다음은 파이썬에서 데이터 카드(Data Card) 자료구조를 구현하고 메타정보를 표현하는 샘플 코드입니다. 이 코드는 데이터 카드의 주요 속성(예: 이름, 설명, 생성 날짜, 업데이트 날짜, 태그, 관련 데이터셋 정보 등)을 포함한 클래스를 정의하고 메타정보를 표현하는 방법을 보여줍니다.

from datetime import datetime
from typing import List, Dict, Optional

class DataCard:
    def __init__(
        self, 
        name: str, 
        description: str, 
        tags: Optional[List[str]] = None, 
        related_datasets: Optional[List[str]] = None, 
        metadata: Optional[Dict[str, str]] = None
    ):
        self.name = name
        self.description = description
        self.created_at = datetime.now()
        self.updated_at = datetime.now()
        self.tags = tags or []
        self.related_datasets = related_datasets or []
        self.metadata = metadata or {}

    def update_description(self, new_description: str):
        self.description = new_description
        self.updated_at = datetime.now()

    def add_tag(self, tag: str):
        if tag not in self.tags:
            self.tags.append(tag)
            self.updated_at = datetime.now()

    def remove_tag(self, tag: str):
        if tag in self.tags:
            self.tags.remove(tag)
            self.updated_at = datetime.now()

    def add_related_dataset(self, dataset_name: str):
        if dataset_name not in self.related_datasets:
            self.related_datasets.append(dataset_name)
            self.updated_at = datetime.now()

    def update_metadata(self, key: str, value: str):
        self.metadata[key] = value
        self.updated_at = datetime.now()

    def display(self):
        print(f"Data Card: {self.name}")
        print(f"Description: {self.description}")
        print(f"Created At: {self.created_at}")
        print(f"Updated At: {self.updated_at}")
        print(f"Tags: {', '.join(self.tags)}")
        print(f"Related Datasets: {', '.join(self.related_datasets)}")
        print(f"Metadata: {self.metadata}")

# Example Usage
if __name__ == "__main__":
    # Create a new data card
    card = DataCard(
        name="Customer Demographics",
        description="Contains customer demographic information for analysis.",
        tags=["demographics", "customer", "analytics"],
        related_datasets=["sales_data", "survey_results"],
        metadata={"owner": "Data Science Team", "source": "Internal Database"}
    )

    # Update description
    card.update_description("Updated demographic data for customer analysis.")

    # Add a new tag
    card.add_tag("updated")

    # Update metadata
    card.update_metadata("last_reviewed", "2025-01-07")

    # Display the data card
    card.display()

주요 기능

  1. 메타정보 관리: metadata 딕셔너리를 통해 키-값 쌍으로 메타정보를 저장.
  2. 업데이트 관리: created_at과 updated_at으로 생성 및 수정 시간을 기록.
  3. 태그 관리: 태그 추가/삭제 기능 포함.
  4. 관련 데이터셋: 관련 데이터셋 목록을 저장.

이 코드는 데이터 카드의 구조를 간단히 표현하며, 실제 구현에서는 사용자 정의 예외 처리, 데이터 검증 등이 추가될 수 있습니다.

+ Recent posts