Logo

파이썬의 typing 내장 모듈로 타입 표시하기

타입 힌트(type hint)를 언어 차원에서 지원하기 위해서 파이썬 버전 3.5에서 typing 모듈이 표준 라이브러리에 추가되었습니다. 이번 포스팅에서는 typing 모듈을 사용해서 파이썬 코드에 타입 어노테이션을 추가하는 방법에 대해서 알아보겠습니다.

파이썬의 타입 어노테이션에 대한 자세한 설명은 관련 포스팅를 참고 바랍니다.

List, Dict, Tuple, Set

타입 어노테이션을 사용하다 보면 리스트, 사전, 튜플, 세트와 같은 파이썬에 내장된 자료구조에 대한 타입을 명시해야 할 때가 있습니다. 이때 그냥, list, dict, tuple, set와 같은 내장 타입을 이용할 수도 있지만, typing 모듈에서 제공하는 List, Dict, Tuple, Set를 사용하면 원소의 타입까지 명시해줄 수 있습니다.

from typing import List

nums: List[int] = [1, 2, 3]
from typing import Dict

temperatures: Dict[str, float] = {"bedroom": 25.1, "kitchen": 23, "bathroom": 19.8}
from typing import Tuple

user: Tuple[int, str, bool] = (3, "Dale", True)
from typing import Set

chars: Set[str] = {"A", "B", "C"}

Python 3.9 업데이트

Python 3.9에서 타입 어노테이션의 사용성이 대폭 개선이 되었습니다. 이제 typing 모듈에서 List, Dict, Tuple, Set를 불러오지 않고, list, dict, tuple, set 내장 타입을 통해 바로 원소의 타입까지 명시해줄 수 있습니다. 🎊

nums: list[int] = [1, 2, 3]
temperatures: dict[str, float] = {"bedroom": 25.1, "kitchen": 23, "bathroom": 19.8}
user: tuple[int, str, bool] = (3, "Dale", True)
chars: set[str] = {"A", "B", "C"}

Final

재할당이 불가능한 변수, 즉 상수에 대한 타입 어노테이션을 추가할 때는 typing 모듈의 Final을 사용합니다.

from typing import Final

TIME_OUT: Final[int] = 10

Union

여러 개의 타입이 허용될 수 있는 상황에서는 typing 모듈의 Union을 사용할 수 있습니다.

from typing import Union


def toString(num: Union[int, float]) -> str:
    return str(num)
>>> toString(1)
'1'
>>> toString(1.5)
'1.5'

Python 3.10 업데이트

Python 3.10에서는 | 연산자로 typing 모듈의 Union을 대체할 수 있게 되었습니다. 따라서 위 코드는 다음과 같이 간소화할 수 있습니다. 🎉

def toString(num: int | float) -> str:
    return str(num)

Optional

typing 모듈의 OptionalNone이 허용되는 함수의 매개 변수에 대한 타입을 명시할 때 유용합니다.

from typing import List, Optional

def repeat(message: str, times: Optional[int] = None) -> List[str]:
    if times:
        return [message] * times
    else:
        return [message]

위 예제에서, Optional[int]Union[int, None]과 동일한 효력을 갖습니다.

>>> repeat("Hi", 3)
['Hi', 'Hi', 'Hi']
>>> repeat("Hi")
['Hi', 'Hi', 'Hi']

Callable

파이썬에서는 함수를 일반 값처럼 변수에 저장하거나 함수의 인자로 넘기거나 함수의 반환값으로 사용할 수 있습니다. typing 모듈의 Callable은 이러한 함수에 대한 타입 어노테이션을 추가할 때 사용합니다.

예를 들어, 아래 repeat 함수는 첫 번째 매개 변수 greet를 통해 함수를 인자로 받고 있는데요. 매개 변수에 타입 어노테이션 Callable[[str], str]를 추가해줌으로써, str 타입의 인자를 하나 받고, 결과값을 str로 반환하는 함수를 나타내고 있습니다.

from typing import Callable

def repeat(greet: Callable[[str], str], name: str, times: int = 1) -> None:
    for _ in range(times):
        print(greet(name))

repeat 함수를 호출할 때 넘길 람다 함수를 작성할 때도 동일한 타입 어노테이션을 사용할 수 있습니다.

>>> repeat(lambda name: f"Hi, {name}!", "Python", 2)
Hi, Python!
Hi, Python!

Iterable, Sequence, Mapping, MutableMapping

어떤 함수의 매개 변수에 타입을 표시해 줄 때는 추상적으로 명시해주는 것이 유리한 경우가 많습니다. 예를 들어, 아래 toStrings() 함수는 nums 매개 변수의 타입을 List[int] 대신에 Iterable[int]로 명시해주고 있습니다.

from typing import Iterable, List

def toStrings(nums: Iterable[int]) -> List[str]:
    return [str(x) for x in nums]

따라서 이 함수는 리스트 뿐만 아니라 튜플, 세트까지 처리할 수 있는 유연한 API를 가지게 되었습니다.

>>> toStrings([1, 2, 3])
['1', '2', '3']
>>> toStrings((1, 2, 3))
['1', '2', '3']
>>> toStrings({1, 2, 3})
['1', '2', '3']

typing 모듈은 Iterable 뿐만 아니라 Sequence, Mapping, MutableMapping와 같은 다른 추상 타입을 지원하고 있으니 한 번 활용해보시면 좋을 것 같습니다.

전체 코드

본 포스팅에서 제가 작성한 전체 코드는 아래에서 직접 확인하고 실행해보실 수 있습니다.

https://dales.link/j23

마치면서

지금까지 파이썬 코드에 타입 어노테이션을 추가할 때 typing 내장 모듈을 어떻게 활용할 수 있는지 살펴보았습니다.

typing 모듈을 사용할 때 한 가지 주의할 점은 타입 어노테이션(type annotation)을 추가한다고 해서 프로그래밍 언어 차원에서 어떤 제약이 발생하는 것은 아니라는 것입니다. 따라서, 타입 어노테이션을 추가한 코드를 상대로 타입을 검증하기 위해서는 Mypy와 같은 정적 타입 검사기를 사용하는 것을 고려하셔야 겠습니다. 이 부분에 대해서는 별도 포스팅에서 자세히 다루었으니 참고 바랍니다.

마지막으로, typing 모듈에 대한 좀 더 자세한 내용은 파이썬 공식 레퍼런스를 참고 바랍니다.