제네릭을 활용한 Python TypedDict
원문은 Alex O'Callaghan님이 에 게재했습니다. 이 블로그 구독하기
Python은 3.5에서 타입 힌트 지원을 추가했지만, 값에 제네릭 타입을 사용해 dict에 타입을 지정하는 것은 의외로 까다롭다.
고정된 키 집합을 가진 딕셔너리에 대한 타입 힌트를 정의하는 것은 typing 모듈의 TypedDict 클래스를 사용하면 꽤 간단하다:
from typing import TypedDict
class Book(TypedDict):
id: int
name: str
book: Book = {"id": 123, "name": "To Kill A Mockingbird"}다음 한 줄을 추가하면:
not_a_book: Book = {"something": "A book doesn't have"}이 코드를 mypy로 실행하면 다음과 같은 결과가 나온다:
$ python -m mypy type-dict.py
type-dict.py:9: error: Missing keys ("id", "name") for TypedDict "Book" [typeddict-item]
type-dict.py:9: error: Extra key "something" for TypedDict "Book" [typeddict-unknown-key]
Found 2 errors in 1 file (checked 1 source file)아주 간단하다!
typing 모듈은 제네릭 클래스를 지원하기 위해 Generic과 TypeVar도 제공한다. 필자의 경우 value 키의 타입이 가변적인 중첩 dict를 위한 제네릭 클래스를 정의하고 싶었다. 앞서의 book 예제를 확장하면 다음과 같다:
from typing import TypeVar, Generic, TypedDict
T = TypeVar('T')
class Attribute(TypedDict, Generic[T]):
value: T
class Book(TypedDict):
id: Attribute[int]
name: Attribute[str]
book: Book = {"id": {"value": 123}, "name": {"value": "To Kill A Mockingbird"}}mypy로 타입 검사를 하면 완벽하게 동작한다! 하지만 직접 실행해 보면...
$ python --version
Python 3.10.12
$ python type-dict-generic.py
Traceback (most recent call last):
File "/home/aocallaghan/exp/py-type-dict/type-dict-generic.py", line 5, in <module>
class Attribute(TypedDict, Generic[T]):
File "/home/aocallaghan/.pyenv/versions/3.10.12/lib/python3.10/typing.py", line 2348, in __new__
raise TypeError('cannot inherit from both a TypedDict type '
TypeError: cannot inherit from both a TypedDict type and a non-TypedDict base classPython 3.10에서는 TypedDict 타입과 다른 베이스 클래스를 동시에 상속받을 수 없다. 하지만 이 문제는 Python 3.11에서 수정되었다:
$ python --version
Python 3.11.4
$ python type-dict-generic.py안타깝게도 3.11 미만 버전에서는 이를 간단하게 구현할 방법이 없는 것 같다. 한 가지 방법은 Enum 클래스를 사용해 키를 표현하는 것이다:
from enum import Enum, auto
from typing import TypeVar, TypedDict
T = TypeVar('T')
class AttributeKeys(Enum):
value = auto()
class Book(TypedDict):
id: dict[AttributeKeys, int]
name: dict[AttributeKeys, str]
book: Book = {"id": {AttributeKeys.value: 123}, "name": {AttributeKeys.value: "To Kill A Mockingbird"}}
not_a_book: Book = {"something": "A book doesn't have"}글을 무작위로 읽기
댓글
로그인하고 댓글 남기기