반드시 구현해야 하는 인터페이스(규약)을 정의하기 위한 클래스
"이 클래스를 상속받는 모든 자식 클래스는 특정 메서드를 반드시 구현해야 한다"
추상 클래스는 객체 생성이 불가능하다.
# 실무 예제
# 결제 시스템
from abc import ABC, abstractmethod
class Payment(ABC):
@abstractmethod
def pay(self, amount):
pass
# 인터페이스 강제 : 모든 결제 클래스는 pay()를 구현해야 함 (260628)
# 카드 결제
class CardPayment(Payment):
def pay(self, amount):
print(f"{amount}원 카드 결제")
# 카카오페이
class KaKaoPayment(Payment):
def pay(self, amount):
print(f"{amount}원 카카오페이 결제")
# 사용 예제
def checkout(payment: Payment):
payment.pay(10000)
checkout(CardPayment())
# 10000원 카드 결제
checkout(KaKaoPayment())
# 10000원 카드 결제
10000원 카카오페이 결제
Protocol 은 파이썬 3.8부터 typing 모듈에 추가된 기능
상속 여부와 상관없이 필요한 메서드만 가지고 있으면 동일한 타입으로 취급하는
구조적 타이핑(Structural Typing)을 지원한다.
이 클래스를 상속했는가를 보지않고,
이 메서드를 가지고 있는가를 본다. : 필요한 메서드만 있으면 같은 타입으로 취급하겠다.
# ABC와 Protocol 비교 예제
# ABC : 구현 강제, 런타임 안전
# 반드시 상속 필요
from abc import ABC, abstractmethod
class Animal(ABC):
@abstractmethod
def speak(self):
pass
class Dog(Animal): # 상속 필요
def speak(self):
return "멍멍"
myDog = Dog()
myDog.speak()
# '멍멍'
"나를 상속해야 한다."
"상속은 필요 없고, 필요한 메서드만 가지고 있으면 된다."
Protocol은 파이썬의 덕 타이핑(Duck Typing)을 타입 시스템으로 공식화한 기능이라고 이해하면 됩니다.
"오리처럼 걷고, 오리처럼 울면, 그것은 오리다."
"speak() 메서드가 있으면, 그것은 Speaker다."
# Protocol
# 상속 필요없음, 매우 유연함
# 덕 타이핑
# 런타임 강제가 약하다. 타입 체커가 있어야 진가가 나타남
from typing import Protocol
class Speaker(Protocol):
def speak(self) -> str:
... # 점 3개 : pass와는 다르다, 구현할 생각이 없고, 선언만 한다는 의미 (260628)
# (점 세 개)는 Ellipsis 객체(Ellipsis Object)라고 한다. -> 파이썬의 문법이다.
# 상속하지 않은 일반 클래스
class Dog:
def speak(self) -> str:
return "멍멍"
class Cat:
def speak(self) -> str:
return "야옹"
class Fish:
pass # speak()가 없는 클래스
# Speaker 타입을 받는 함수
def make_sound(animal: Speaker):
print(animal.speak())
dog = Dog()
cat = Cat()
fish = Fish()
# 함수 호출
make_sound(dog)
make_sound(cat)
make_sound(fish)
멍멍
야옹
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
Cell In[22], line 35
31
32 # 함수 호출
33 make_sound(dog)
34 make_sound(cat)
---> 35 make_sound(fish)
Cell In[22], line 26
25 def make_sound(animal: Speaker):
---> 26 print(animal.speak())
AttributeError: 'Fish' object has no attribute 'speak'
최근 Python 생태계(특히 FastAPI, Pydantic, 클린 아키텍처, DI)에서는 Protocol 사용이 점점 늘어나고 있습니다.
다만 용도는 다릅니다.
프레임워크의 핵심 인터페이스
플러그인 시스템
강제적인 상속 구조가 필요한 경우
Repository 패턴
Logger
Cache
Notifier
의존성 주입(DI)
테스트용 Fake/Mock 객체
제가 실무 Python 프로젝트(FastAPI, Pydantic 기반 백엔드)를 기준으로 체감 비율을 말하면,
일반 클래스 70%
dataclass/BaseModel 15%
Protocol 10%
ABC 5%
정도이며, 새로운 코드일수록 ABC보다 Protocol을 선호하는 추세가 있습니다. 다만 라이브러리나 프레임워크 자체를 설계할 때는 여전히 ABC가 많이 사용됩니다.