추상 기반 클래스(Abstract Base Class, ABC)는 자식 클래스가 반드시 구현해야 할 메서드를 선언해 두는 클래스다. 추상 메서드를 하나라도 구현하지 않은 클래스는 인스턴스를 만들 때 TypeError가 난다.
from abc import ABC, abstractmethod
class PaymentGateway(ABC):
@abstractmethod
def charge(self, amount: int) -> str: ...
def refund_all(self, ids): # 구현이 있는 일반 메서드도 둘 수 있다
return [self.refund(i) for i in ids]
@abstractmethod
def refund(self, payment_id: str) -> None: ...
class FakeGateway(PaymentGateway):
def charge(self, amount): return "ok"
FakeGateway() # TypeError: Can't instantiate abstract class ... refund- 오류는 클래스를 정의할 때가 아니라 인스턴스를 만들 때 난다
ABC를 상속하는 것은metaclass=ABCMeta를 지정하는 것과 같다. 메타클래스(metaclass)는 "클래스를 만드는 클래스"로, 따로 지정하지 않으면type이 쓰인다.ABCMeta가 추상 메서드 구현 여부를 검사한다collections.abc에Iterable,Mapping같은 표준 ABC가 있어isinstance(x, Iterable)처럼 쓴다
Protocol과 비교
파이썬은 덕 타이핑(duck typing) 언어라 "이 메서드가 있으면 그 타입으로 친다"가 기본이다. 상속을 강제하지 않고 모양만 맞추면 되는 타입 검사가 필요하면 typing.Protocol이 더 가볍다. 정적 타입 검사기가 구조로 호환성을 판단한다는 점에서 타입스크립트의 구조적 타이핑과 같다.
- ABC: 명시적으로 상속해야 하고, 런타임에 강제된다
- Protocol: 상속이 필요 없고, 주로 정적 검사기(mypy 등)가 확인한다
언제 쓰나
여러 구현을 갈아 끼우는 플러그인 구조, 테스트용 가짜 구현을 만들 때 인터페이스를 고정하는 데 쓴다. 고수준 코드가 구체 구현이 아니라 추상에 기대게 하는 의존성 역전 원칙이나, 같은 인터페이스 뒤에서 알고리즘을 바꾸는 전략 패턴과 함께 쓰인다. 하위 클래스가 약속을 지켜야 한다는 점은 리스코프 치환 원칙을 본다.
출처: abc 모듈 문서 · Python 용어집: abstract base class · typing.Protocol