PHpullh
학습 라이브러리/Python/Protocol 기반 플러그인 시스템

PYTHON · 디자인패턴

Protocol 기반 플러그인 시스템

느슨한 결합(loose coupling)과 확장성 있는 플러그인 아키텍처를 구현합니다.

디자인패턴중급Protocolpluginfactoryloose-coupling@runtime_checkable

핵심 설명

느슨한 결합(loose coupling)과 확장성 있는 플러그인 아키텍처를 구현합니다.

Python code

from typing import Protocol, runtime_checkable
from pathlib import Path

# 플러그인 인터페이스 정의
@runtime_checkable
class Exporter(Protocol):
    def export(self, data: list, path: Path) -> None: ...
    def extension(self) -> str: ...

# 구현체들 (Exporter를 명시적으로 상속하지 않음)
class CsvExporter:
    def export(self, data: list, path: Path) -> None:
        import csv
        with open(path, "w", newline="") as f:
            if data:
                writer = csv.DictWriter(f, fieldnames=data[0])
                writer.writeheader()
                writer.writerows(data)

    def extension(self) -> str:
        return ".csv"

class JsonExporter:
    def export(self, data: list, path: Path) -> None:
        import json
        path.write_text(json.dumps(data, indent=2, ensure_ascii=False))

    def extension(self) -> str:
        return ".json"

# 팩토리
_exporters: dict[str, Exporter] = {
    "csv":  CsvExporter(),
    "json": JsonExporter(),
}

def get_exporter(fmt: str) -> Exporter:
    if fmt not in _exporters:
        raise ValueError(f"지원하지 않는 포맷: {fmt}")
    return _exporters[fmt]

# 사용
data = [{"name": "Alice", "score": 95}]
for fmt in ["csv", "json"]:
    exp = get_exporter(fmt)
    print(isinstance(exp, Exporter))  # True

학습 팁

@runtime_checkable을 추가하면 isinstance(obj, Protocol) 검사가 가능해집니다. 단, 메서드 시그니처까지는 검사하지 않습니다.

주의할 점

Protocol 검사는 메서드 존재 여부만 확인합니다. 타입 힌트나 반환값은 정적 분석 도구(mypy)만 검사합니다.

자주 묻는 질문

Protocol 기반 플러그인 시스템란 무엇인가요?

느슨한 결합(loose coupling)과 확장성 있는 플러그인 아키텍처를 구현합니다.

Protocol 기반 플러그인 시스템 학습 시 주의할 점은 무엇인가요?

Protocol 검사는 메서드 존재 여부만 확인합니다. 타입 힌트나 반환값은 정적 분석 도구(mypy)만 검사합니다.