PEP593: Flexible function and variable annotations

2023년 06월 24일

pep

# 파이썬# PEP593

PEP 593: Flexible function and variable annotations

초록 (Abstract)

PEP593은 PEP 484에서 소개한 타입 힌트에 임의의 메타데이터(metadata)를 추가한 확장된 타입 어노테이션에 대한 메커니즘을 소개한다.

동기 (Motivation)

PEP 484 provides a standard semantic for the annotations introduced in PEP 3107.

  • PEP 484는 PEP 3107에서 도입된 어노테이션에 대한 표준 시멘틱을 제공하기 위한 것이다.
  • PEP 3107은 Function Annotations에 대한 내용으로 파이썬 함수에 메타데이터를 추가할 수 있게 해준다.
  • 즉, 이 PEP 484는 과거에 도입된 Function Annotations(PEP593)에 대한 표준화된 방식을 제안하는 것

PEP 484 is prescriptive but it is the de facto standard for most of the consumers of annotations; in many statically checked code bases, where type annotations are widely used, they have effectively crowded out any other form of annotation.

  • PEP 484는 규범적이지만 대부분의 어노테이션 소비자를 위한 사실상의 표준이다.
  • 타입 어노테이션이 많이 사용되는 정적기반으로 검사된 코드에서 구축 효과로 인해 다른 형태의 타입 어노테이션의 사용이 감소되었다.
  • crowed out: 구축 (crowding out) 또는 구축 효과는 정부 지출을 증가시키면 이자율이 상승하여 민간투자가 감소되는 현상 - 위키백과

Some of the use cases for annotations described in PEP 3107 (database mapping, foreign languages bridge) are not currently realistic given the prevalence of type annotations.

  • PEP 3107의 사용 사례에서 언급된 Database query mapping과 같은 사용 사례는 현재로서는 사용하기에 어렵다.

Furthermore, the standardisation of type annotations rules out advanced features only supported by specific type checkers.

  • 타입 어노테이션의 표준화는 특정 타입 검사기에서만 지원되는 고급 기능을 제외한다.
  • 표준화 도입을 통해 확장된 형태의 타입 어노테이션의 사용이 제한되고있다는 것

근거 (Rationale)

This PEP adds an Annotated type to the typing module to decorate existing types with context-specific metadata.

  • 이 PEP는 기존에 존재하던 타입에 특정 컨텍스트에 대한 메타데이터를 추가하기 위해 typing 모듈에 Annotated 타입을 추가한다.

Specifically, a type T can be annotated with metadata x via the typehint Annotated[T, x].

  • 특히, 타입 T는 Annotated[T, x] 타입 힌트를 통해 메타데이터 x로 주석을 달 수 있다.

This metadata can be used for either static analysis or at runtime.

  • 메타데이터는 정적 분석 혹은 런타임에 사용될 수 있다고 한다.
  • 자동완성, 타입 검사 등의 정적 분석에 사용될 수 있고, 런타임에는 메타데이터를 사용할 수 있다.

If a library (or tool) encounters a typehint Annotated[T, x] and has no special logic for metadata x, it should ignore it and simply treat the type as T.

Unlike the no_type_check functionality that currently exists in the typing module which completely disables typechecking annotations on a function or a class, the Annotated type allows for both static typechecking of T (e.g., via mypy or Pyre, which can safely ignore x) together with runtime access to x within a specific application.

The introduction of this type would address a diverse set of use cases of interest to the broader Python community.

Motivating examples

Combining runtime and static uses of annotations

There’s an emerging trend of libraries leveraging the typing annotations at runtime (e.g.: dataclasses); having the ability to extend the typing annotations with external data would be a great boon for those libraries.

Here’s an example of how a hypothetical module could leverage annotations to read c structs:

UnsignedShort = Annotated[int, struct2.ctype('H')]
SignedChar = Annotated[int, struct2.ctype('b')]

class Student(struct2.Packed):
    # mypy typechecks 'name' field as 'str'
    name: Annotated[str, struct2.ctype("<10s")]
    serialnum: UnsignedShort
    school: SignedChar

# 'unpack' only uses the metadata within the type annotations
Student.unpack(record)
# Student(name=b'raymond   ', serialnum=4658, school=264)

Lowering barriers to developing new typing constructs

Typically when adding a new type, a developer need to upstream that type to the typing module and change mypy, PyCharm, Pyre, pytype, etc… This is particularly important when working on open-source code that makes use of these types, seeing as the code would not be immediately transportable to other developers’ tools without additional logic. As a result, there is a high cost to developing and trying out new types in a codebase. Ideally, authors should be able to introduce new types in a manner that allows for graceful degradation (e.g.: when clients do not have a custom mypy plugin), which would lower the barrier to development and ensure some degree of backward compatibility.

For example, suppose that an author wanted to add support for tagged unions to Python. One way to accomplish would be to annotate TypedDict in Python such that only one field is allowed to be set:

Currency = Annotated[
    TypedDict('Currency', {'dollars': float, 'pounds': float}, total=False),
    TaggedUnion,
]

This is a somewhat cumbersome syntax but it allows us to iterate on this proof-of-concept and have people with type checkers (or other tools) that don’t yet support this feature work in a codebase with tagged unions. The author could easily test this proposal and iron out the kinks before trying to upstream tagged union to typing, mypy, etc. Moreover, tools that do not have support for parsing the TaggedUnion annotation would still be able to treat Currency as a TypedDict, which is still a close approximation (slightly less strict).

Reference

© 2025, 미나리와 함께 만들었음