PHpullh
학습 라이브러리/Python/Protocol — 구조적 서브타이핑

PYTHON · 객체지향

Protocol — 구조적 서브타이핑

typing.Protocol은 Go의 인터페이스처럼 구조적 서브타이핑(덕 타이핑의 정적 버전)을 지원합니다. 클래스가 명시적으로 상속하지 않아도, 필요한 메서드와 속성만 가지면 해당 프로토콜을 만족합니다.

객체지향고급protocolstructural-subtypingduck-typingtype-hints

핵심 설명

typing.Protocol은 Go의 인터페이스처럼 구조적 서브타이핑(덕 타이핑의 정적 버전)을 지원합니다. 클래스가 명시적으로 상속하지 않아도, 필요한 메서드와 속성만 가지면 해당 프로토콜을 만족합니다.

Python code

from typing import Protocol, runtime_checkable, Iterable

# 1. 기본 Protocol 정의
@runtime_checkable  # isinstance() 체크 가능
class Drawable(Protocol):
    def draw(self) -> str: ...

class Resizable(Protocol):
    width: float
    height: float
    def resize(self, factor: float) -> None: ...

# Protocol을 상속하지 않아도 구조만 맞으면 OK
class Circle:
    def __init__(self, radius: float):
        self.radius = radius
        self.width = radius * 2
        self.height = radius * 2

    def draw(self) -> str:
        return f"○ (r={self.radius})"

    def resize(self, factor: float) -> None:
        self.radius *= factor
        self.width = self.radius * 2
        self.height = self.radius * 2

class Rectangle:
    def __init__(self, w: float, h: float):
        self.width = w
        self.height = h

    def draw(self) -> str:
        return f"□ ({self.width}x{self.height})"

    def resize(self, factor: float) -> None:
        self.width *= factor
        self.height *= factor

# 2. Protocol을 타입 힌트로 사용
def render_all(shapes: Iterable[Drawable]) -> None:
    for shape in shapes:
        print(f"  렌더링: {shape.draw()}")

def scale_all(shapes: Iterable[Resizable], factor: float) -> None:
    for shape in shapes:
        shape.resize(factor)

# 3. runtime_checkable 활용
shapes = [Circle(5), Rectangle(10, 20)]

for s in shapes:
    print(f"Drawable? {isinstance(s, Drawable)}")
    print(f"Resizable? {isinstance(s, Resizable)}")

print("\n원본:")
render_all(shapes)
scale_all(shapes, 0.5)
print("축소 후:")
render_all(shapes)

학습 팁

@runtime_checkable을 붙여야 isinstance() 체크가 가능합니다. 하지만 런타임 검사는 메서드 존재 여부만 확인하고 시그니처는 검증하지 않으므로 mypy 같은 정적 타입 체커와 함께 사용하세요.

주의할 점

Protocol은 isinstance()로 속성(attribute) 존재를 검사하지 못합니다. 메서드만 확인되므로 속성 기반 프로토콜은 정적 타입 체커에서만 완전히 검증됩니다.

자주 묻는 질문

Protocol — 구조적 서브타이핑란 무엇인가요?

typing.Protocol 은 Go의 인터페이스처럼 구조적 서브타이핑(덕 타이핑의 정적 버전)을 지원합니다. 클래스가 명시적으로 상속하지 않아도, 필요한 메서드와 속성만 가지면 해당 프로토콜을 만족합니다.

Protocol — 구조적 서브타이핑 학습 시 주의할 점은 무엇인가요?

Protocol은 isinstance() 로 속성(attribute) 존재를 검사하지 못합니다. 메서드만 확인되므로 속성 기반 프로토콜은 정적 타입 체커에서만 완전히 검증됩니다.