typing — 타입 힌트 지원
typing — 타입 힌트 지원
참고: Python 런타임은 함수와 변수 타입 주석(annotation)을 강제하지 않아요. 이것들은 타입 검사기, IDE, 린터 같은 서드파티 도구에서 사용할 수 있어요.
이 모듈은 타입 힌트에 대한 런타임 지원을 제공해요. 버전 3.5에서 추가되었어요.
본문
다음 함수를 생각해보세요:
def surface_area_of_cube(edge_length: float) -> str:
return f"The surface area of the cube is {6 * edge_length ** 2}."
suraface_area_of_cube 함수는 타입 힌트 edge_length: float가 나타내는 대로 float의 인스턴스가 될 것으로 기대되는 인자를 받아요. -> str 힌트가 나타내는 대로 str 인스턴스를 반환할 것으로 기대돼요. 타입 힌트는 float나 str 같은 간단한 클래스일 수 있지만 더 복잡할 수도 있어요. typing 모듈은 더 고급 타입 힌트의 어휘를 제공해요.
새 기능이 typing 모듈에 자주 추가돼요. typing_extensions 패키지는 이러한 새 기능을 이전 Python 버전에 백포트해 제공해요.
타입 별칭 (Type aliases)
타입 별칭은 TypeAliasType의 인스턴스를 만드는 type 문을 사용해 정의돼요. 이 예에서 Vector와 list[float]는 정적 타입 검사기에 의해 동등하게 처리돼요:
type Vector = list[float]
def scale(scalar: float, vector: Vector) -> Vector:
return [scalar * num for num in vector]
# 타입 검사 통과; float 목록은 Vector로 자격이 됨
new_vector = scale(2.0, [1.0, -4.2, 5.4])
타입 별칭은 복잡한 타입 시그니처를 단순화하는 데 유용해요. type 문은 Python 3.12에서 새로 나왔어요. 이전 버전과의 호환을 위해 타입 별칭은 단순 할당(Vector = list[float])으로 만들거나 TypeAlias로 표시할 수 있어요.
타입 별칭은 두 타입이 서로 동등함을 선언해요. type Alias = Original은 정적 타입 검사기가 모든 경우에 Alias를 Original과 정확히 동등하게 취급하게 해요.
NewType
NewType 헬퍼로 구별되는 타입을 만들어요:
from typing import NewType
UserId = NewType('UserId', int)
some_id = UserId(524313)
정적 타입 검사기는 새 타입을 원래 타입의 하위 클래스인 것처럼 취급해요. 이는 논리 오류를 잡는 데 유용해요. Derived = NewType('Derived', Base) 문은 Derived를 전달하는 매개변수를 즉시 반환하는 호출 가능하게 만든다. 즉 런타임에 some_value is Derived(some_value)가 항상 true예요. Derived의 하위 타입을 만드는 것은 유효하지 않아요.
반면 NewType은 한 타입을 다른 타입의 하위 타입으로 선언해요. Derived = NewType('Derived', Original)은 정적 타입 검사기가 Derived를 Original의 하위 클래스로 취급하게 해요. 이는 최소한의 런타임 비용으로 논리 오류를 방지하려 할 때 유용해요.
호출 가능 객체 주석 (Annotating callable objects)
함수 — 또는 다른 호출 가능 객체 — 는 collections.abc.Callable 또는 더 이상 사용되지 않는 typing.Callable을 사용해 주석을 달 수 있어요. Callable[[int], str]은 int 타입의 단일 매개변수를 받고 str을 반환하는 함수를 나타내요. 구독 구문은 항상 정확히 두 값(인자 목록과 반환 타입)과 함께 사용해야 해요.
리터럴 줄임표 ...가 인자 목록으로 주어지면, 임의의 매개변수 목록을 가진 호출 가능이 허용됨을 나타내요:
def concat(x: str, y: str) -> str:
return x + y
x: Callable[..., str]
x = str # OK
x = concat # OK
Callable은 가변 인자의 함수, 오버로드된 함수, 키워드 전용 매개변수가 있는 함수 같은 복잡한 시그니처를 표현할 수 없어요. 그러나 이러한 시그니처는 __call__() 메서드를 가진 Protocol 클래스를 정의해 표현할 수 있어요. 다른 호출 가능을 인자로 받는 호출 가능은 ParamSpec을 사용해 그 매개변수 타입이 서로 의존함을 나타낼 수 있고, Concatenate 연산자를 사용할 수 있어요.
제네릭 (Generics)
컨테이너에 보관된 객체의 타입 정보는 제네릭 방식으로 정적으로 추론될 수 없으므로, 표준 라이브러리의 많은 컨테이너 클래스는 컨테이너 요소의 예상 타입을 나타내는 구독을 지원해요:
from collections.abc import Mapping, Sequence
class Employee: ...
def notify_by_email(employees: Sequence[Employee], overrides: Mapping[str, str]) -> None: ...
제네릭 함수와 클래스는 타입 매개변수 구문으로 매개변수화할 수 있어요:
from collections.abc import Sequence
def first[T](l: Sequence[T]) -> T: # 함수는 TypeVar "T"에 대해 제네릭
return l[0]
또는 TypeVar 팩토리를 직접 사용해요:
from typing import TypeVar
U = TypeVar('U') # 타입 변수 "U" 선언
def second(l: Sequence[U]) -> U: # 함수는 TypeVar "U"에 대해 제네릭
return l[1]
튜플 주석 (Annotating tuples)
Python의 타입 시스템은 다른 대부분의 컨테이너에서 모든 요소가 같은 타입이라고 가정해요. 그러나 관용적인 Python 코드에서 튜플은 요소가 모두 같은 타입이 아닌 것이 흔해요. 이 때문에 tuple은 Python의 타입 시스템에서 특별히 처리돼요. tuple은 임의의 수의 타입 인자를 받아요.
어떤 길이일 수 있고 모든 요소가 같은 타입 T인 튜플을 나타내려면 리터럴 줄임표 ...를 사용해요: tuple[T, ...]. 빈 튜플은 tuple[()]을 사용해요. 일반 tuple을 주석으로 사용하는 것은 tuple[Any, ...]를 사용하는 것과 동등해요.
클래스 객체의 타입 (The type of class objects)
C로 주석을 단 변수는 C 타입의 값을 받을 수 있어요. 반면 type[C]로 주석을 단 변수는 클래스 그 자체인 값을 받아요. type[C]는 공변(covariant)이에요. type의 유일한 합법적 매개변수는 클래스, Any, 타입 변수, 그리고 이들의 유니언이에요. type[Any]는 Python의 메타클래스 계층의 루트인 type과 동등해요.
제너레이터와 코루틴 주석 (Annotating generators and coroutines)
제너레이터는 제네릭 타입 Generator[YieldType, SendType, ReturnType]으로 주석을 달 수 있어요. 표준 라이브러리의 다른 많은 제네릭 클래스와 달리 Generator의 SendType은 공변이 아니라 반공변(contravariant)으로 동작해요. SendType과 ReturnType 매개변수는 기본값이 None이에요.
코루틴은 Coroutine[YieldType, SendType, ReturnType]으로 주석을 달 수 있어요.
유니언 (Unions)
두 개 이상의 타입의 유니언은 | 연산자(int | str)나 typing.Union을 사용해 표현할 수 있어요. 다음 두 문은 서로 동일해요:
int | str
Union[int, str]
기타 특수 형태 (Special forms)
- Any — 제한 없는 타입.
Any타입의 값은 모든 타입과 호환되고, 모든 타입은Any와 호환돼요. - Literal — 특정 리터럴 값만 허용하는 타입을 나타내요.
- Optional[X] —
X | None과 동등. - TypeVar — 타입 변수.
- Protocol — 구조적 서브타이핑을 위한 프로토콜.
- TypedDict — dict의 타입 힌트.
- NamedTuple — namedtuple의 타입 힌트.
- overload — 오버로드된 함수 정의.
- Final — 최종 타입 지정.
- ClassVar — 클래스 변수를 나타내요.
- Self — 메서드의 반환 타입이 클래스 인스턴스 자신임을 나타내요.
기타 주제
- Constant types —
Final과ClassVar - Annotating tuples — 다양한 길이의 튜플
- User-defined generic types — 사용자 정의 제네릭 타입
- The type of class objects —
type[C] - Annotating generators and coroutines —
Generator,Coroutine - Type aliases —
type문,TypeAlias - NewType — 구별되는 타입
- Callback protocols —
__call__()메서드를 가진 Protocol - Type parameter syntax — PEP 695 타입 매개변수 구문
typing 모듈의 타입 시스템은 PEP를 통해 표준화되어 있어요. 자세한 내용은 "Specification for the Python Type System"을 참고하세요.