파이썬에서 프로토콜은 정식으로 클래스의 메서드나 속성을 정의하지 않고도 특정 동작을 따르는 객체를 만들기 위한 개념이다. 프로토콜을 사용하면 타입 힌팅과 정적 타입 검사를 더 효과적으로 할 수 있다. 이는 주로 typing
모듈의 Protocol
클래스를 사용하여 정의된다.
기본 사용법
다음은 Protocol
을 사용하여 프로토콜을 정의하고 이를 구현하는 예제이다.
from typing import Protocol
class Flyer(Protocol):
def fly(self) -> None:
...
class Bird:
def fly(self) -> None:
print("Bird is flying")
class Airplane:
def fly(self) -> None:
print("Airplane is flying")
# 사용 예시
def let_it_fly(flyer: Flyer) -> None:
flyer.fly()
bird = Bird()
airplane = Airplane()
let_it_fly(bird) # Bird is flying
let_it_fly(airplane) # Airplane is flying
자세한 설명
Protocol 클래스
Protocol
클래스는 타입 힌팅과 정적 타입 검사를 위해 사용된다. Protocol
을 상속받아 정의된 클래스는 인터페이스처럼 동작하며, 이를 구현하는 클래스는 프로토콜에 정의된 메서드와 속성을 제공해야 한다.
from typing import Protocol
class ExampleProtocol(Protocol):
def method(self) -> None:
...
이 프로토콜을 구현하는 클래스는 method
메서드를 제공해야 한다.
정적 타입 검사
Protocol
을 사용하면 타입 힌팅과 함께 정적 타입 검사를 통해 코드의 일관성을 유지할 수 있다. 이는 mypy
와 같은 타입 검사기를 통해 이루어진다.
프로토콜과 상속
프로토콜은 명시적인 상속 없이도 특정 메서드나 속성을 제공하는 모든 클래스에 적용될 수 있다. 즉, 덕 타이핑(duck typing)을 이용한 형태로 동작한다.
class Swimmer(Protocol):
def swim(self) -> None:
...
class Fish:
def swim(self) -> None:
print("Fish is swimming")
class Human:
def swim(self) -> None:
print("Human is swimming")
# 사용 예시
def let_it_swim(swimmer: Swimmer) -> None:
swimmer.swim()
fish = Fish()
human = Human()
let_it_swim(fish) # Fish is swimming
let_it_swim(human) # Human is swimming
덕 타이핑은 파이썬과 같은 동적 타이핑 언어에서 사용되는 개념으로, 객체의 실제 타입보다 객체의 현재 메서드나 속성에 따라 행동을 결정하는 방식이다. 이는 "오리처럼 걷고 오리처럼 소리내면 그것은 오리일 것이다"라는 철학에 기초한다. 즉, 객체가 특정 인터페이스를 구현했는지 여부를 확인하지 않고, 필요한 메서드나 속성을 가지고 있으면 사용한다.
응용 예제
좀 더 복잡한 예제로, 프로토콜을 사용하여 다양한 형태의 데이터를 읽고 쓰는 인터페이스를 정의해보자.
from typing import Protocol
class DataReader(Protocol):
def read(self) -> str:
...
class DataWriter(Protocol):
def write(self, data: str) -> None:
...
class FileReader:
def __init__(self, filename: str):
self.filename = filename
def read(self) -> str:
with open(self.filename, 'r') as file:
return file.read()
class FileWriter:
def __init__(self, filename: str):
self.filename = filename
def write(self, data: str) -> None:
with open(self.filename, 'w') as file:
file.write(data)
# 사용 예시
def process_data(reader: DataReader, writer: DataWriter) -> None:
data = reader.read()
# 데이터 처리 로직 (예: 모든 텍스트를 대문자로 변환)
processed_data = data.upper()
writer.write(processed_data)
file_reader = FileReader('input.txt')
file_writer = FileWriter('output.txt')
process_data(file_reader, file_writer)