Following system colour scheme Selected dark colour scheme Selected light colour scheme

Python 개선 제안 한국어 번역

PEP 835 – Annotated 타입 메타데이터를 위한 단축 구문

Author:
Till Varoquaux <till.varoquaux at gmail.com>
Sponsor:
Ivan Levkivskyi <levkivskyi at gmail.com>
Discussions-To:
Discourse thread
Status:
Draft
Type:
Standards Track
Topic:
Typing
Created:
12-Jun-2026
Python-Version:
3.16
Post-History:
19-Apr-2026, 18-Jun-2026

Table of Contents

번역·라이선스 안내

이 비공식 한국어 번역은 원문 Copyright 절의 Public Domain or CC0-1.0, whichever is more permissive 조건에 따라 제공합니다. 원저자와 공식 원문은 그대로 표시합니다. 수정되지 않은 기준 원문 · 공식 최신판

초록

이 PEP는 Annotated[T, M]T @ M으로 작성할 수 있도록 타입에 @ 연산자를 오버로드할 것을 제안합니다.

동기

PEP 593 (Annotated)는 널리 채택되었습니다. 주요 프레임워크(FastAPI, Pydantic, SQLAlchemy, msgspec, Typer, beartype)는 이제 이를 표준 타입 메타데이터 메커니즘으로 사용합니다 [1].

그러나 구문이 장황하다는 점은 여전히 채택을 가로막는 장벽입니다.

  1. 라이브러리는 이를 숨기기 위해 별칭을 만듭니다. 프레임워크는 사용자가 Annotated[..., ...] 보일러플레이트에 노출되지 않도록 DSL이나 타입 별칭(예: PositiveInt)을 일상적으로 만듭니다 [2].
  2. 주요 프로젝트는 채택을 미룹니다. PyTorch [3], TorchTyping, Beartype [4]는 텐서 형상에 Annotated를 채택하는 것을 미루었으며, 그 이유로 장황한 구문을 명시적으로 들고 네이티브 언어 차원의 해결책을 기다렸습니다.
  3. 가독성에 영향을 줍니다. PEP 727 논의에서 참가자들은 일상적인 문서화에 Annotated를 의존하면 코드를 읽을 수 없게 되어 PEP가 철회되는 데 기여할 것이라고 경고했습니다 [5].

가장 많이 다운로드된 PyPI 프로젝트 10,000개 중 43.4%가 전이적으로 Annotated에 의존합니다. FastAPI 코드베이스를 새로운 단축 구문으로 마이그레이션하자 2,524 LOC가 제거되었습니다.

컨테이너와 유사한 구문은 Python의 발전 방향에 맞지 않습니다. Python은 typing.Union과 같은 제네릭 래퍼를 |와 같은 연산자(그리고 교집합을 위한 &를 제안하는 방식)로 적극적으로 대체하면서 타입 어노테이션을 타입의 산술로 발전시키고 있습니다.

@ 단축 구문은 구문과 의미를 일치시킵니다. 타입 메타데이터를 후위 연산자로 적용하면 다음과 같은 효과가 있습니다.

  • 중첩을 줄입니다(괄호가 필요하지 않습니다).
  • 토큰 수를 줄입니다(typing.Annotated 가져오기가 필요하지 않습니다).
  • 지역성을 개선합니다(기본 타입이 전면에 그대로 유지됩니다).
  • 타입의 산술을 확장합니다(타입 메타데이터가 제네릭 컨테이너가 아니라 기존 타입 표현식에 대한 연산으로 작동합니다).

이를 통해 간결한 구문과 엄격한 타이핑 간의 충돌을 해결합니다.:

class User(BaseModel):
    # Bad: Early frameworks abused defaults, breaking static analysis
    id: int = Field(gt=0)

    # Verbose: PEP 593 fixed semantics, but hindered adoption
    id: Annotated[int, Field(gt=0)]

    # Proposed: Concise while preserving PEP 593 semantics
    id: int @ Field(gt=0)

연산자로서 @는 네이티브하게 조합됩니다.:

# Inside generics
list[Annotated[str, Field(max_length=50)]]
list[str @ Field(max_length=50)]

# Within a union
Annotated[int, Ge(0)] | Annotated[str, Len(5)]
int @ Ge(0) | str @ Len(5)

# Across an entire union
Annotated[str | None, Field(description="Optional string")]
(str | None) @ Field(description="Optional string")

# Within callables
Callable[[Annotated[int, Ge(0)]], str]
Callable[[int @ Ge(0)], str]

역사적 맥락 및 선행 사례

커뮤니티가 2023년 말 [6]과 2025년 [7]에 대안을 논의했을 때, 논의는 기존 Python decorators와 시각적으로 부합한다는 이유로 @ 연산자 쪽으로 기울었습니다.

타입 메타데이터에 @를 채택하는 것은 정적 타이핑을 위해 런타임 연산자를 용도 변경하는 선례도 따릅니다. 이는 제네릭에 []를 사용하는 것(PEP 585)과 유니언에 |를 사용하는 것(PEP 604)에서 볼 수 있습니다 [8].

후위 구문은 다른 정적 타입 언어의 기능을 반영합니다.

  • C++: 타입에 [[attribute]]를 사용합니다(예: [[nodiscard]] int f();).
  • Java / Kotlin: @Annotation을 사용합니다(예: List<@NonNull String> 또는 val x: @NotNull String).
  • OCaml: [@attribute] 후위 구문을 사용합니다(예: type t = int [@default 0]).

용어

어노테이션과 메타데이터에 관한 논의를 명확히 하기 위해 다음 용어를 사용합니다:

  • 타입 표현식: 예를 들어, x: <this>입니다. 타입 힌트 내에서 유효한 타입으로 평가되는 표현식으로, Typing Specification (PEP 484)에 명시되어 있습니다.
  • 타입 메타데이터: 예를 들어, int @ <this>입니다. Annotated를 통해 타입 표현식에 첨부되는 데이터입니다 (PEP 593, PEP 746).
  • 비-타이핑 어노테이션: 예를 들어, @no_type_checkx: <this>를 감싸는 것입니다. 타입 표현식으로 평가되도록 의도되지 않은 어노테이션입니다(예: 타입 검사기가 무시하는 어노테이션).
  • 심벌 데코레이터: 기반 타입이 아니라 변수 또는 필드 선언에 메타데이터를 직접 적용하는 것입니다. 이러한 구분은 Java와 같은 언어에서 잘 확립되어 있습니다:
    class Application {
        // Field Decorator (symbol decorator)
        @Inject
        private Service s;
    
        // Type Decorator (type metadata)
        private @NonNull String name;
    }
    
  • 심벌 메타데이터(또는 필드 메타데이터): 심벌에 첨부되는 메타데이터입니다. 타입 메타데이터와 구별됩니다. 타입 자체가 아니라 변수의 특정 인스턴스에 적용되기 때문입니다.

명세

제안된 구문은 __matmul__ 연산자를 사용하여 타입에 메타데이터를 첨부합니다.:

# Current syntax
x: Annotated[int, Range(0, 10)]

# Proposed shorthand
x: int @ Range(0, 10)

연산자 우선순위

@| 합집합 연산자(PEP 604)보다 강하게 결합하므로, 괄호 없이 합집합 내 특정 타입에 서로 다른 제약 조건을 직접 첨부할 수 있습니다. 예를 들어, 미국 우편번호는 5자리 정수 또는 5자 문자열일 수 있습니다.:

zip_code: int @ Ge(10000) @ Le(99999) | str @ Len(5)

전체 합집합에 메타데이터를 첨부하려면 괄호를 사용하십시오.:

# Attaches only to 'str'
int | str @ Metadata    # equivalent to: int | Annotated[str, Metadata]

# Attaches to the entire union
(int | str) @ Metadata  # equivalent to: Annotated[int | str, Metadata]

여러 메타데이터 평탄화

연결된 메타데이터는 결과 Annotated 객체를 평탄화합니다. T @ m1 @ m2Annotated[T, m1, m2]로 평가되며, 결코 Annotated[Annotated[T, m1], m2]로 평가되지 않습니다. 이는 typing.Annotated의 기존 런타임 동작을 반영합니다.

좌측 피연산자가 기존 Annotated 타입인 경우에도 동일한 논리가 적용됩니다.:

Annotated[int, m1] @ m2  # AnnotatedType(int, m1, m2) (flattened)

런타임 동작

@types.AnnotatedType을 생성합니다(새로운 내장 C 타입입니다). 기존 typing.Annotated는 이 타입과 통합됩니다. typing.Annotated[X, Y]X @ Y는 완전히 동일한 객체를 반환합니다:

>>> type(int @ Field()) is type(Annotated[int, Field()])
True
>>> typing.Annotated is types.AnnotatedType
True

AnnotatedType 객체는 다음 속성을 제공합니다:

  • __origin__: 기본 타입입니다(예: int).
  • __metadata__: 메타데이터 항목의 튜플입니다.
  • __args__: (origin, *metadata) 튜플이며, typing.get_args()와의 호환성을 위한 것입니다.
  • __parameters__: 해당 타입의 고유한 자유 타입 매개변수의 튜플입니다.

AnnotatedTyperepr()는 약식 구문을 사용합니다:

>>> int @ Field(gt=0)
int @ Field(gt=0)

None 처리

런타임 버그가 가려지는 것을 방지하기 위해 NoneType는 명시적으로 __matmul__을 구현하지 않습니다.

예를 들어, 개발자가 행렬 곱셈 전에 None을 확인하는 것을 잊을 수 있습니다:

 def matmul_arrays(a: np.array | None, b: np.array):
     return a @ b  # oops, forgot to check for None

NoneType.__matmul__이 존재한다면, 이는 AnnotatedType를 조용히 반환하고 TypeError를 발생시키지 않습니다.

NoneType__matmul__이 없으므로, None @ Metadata와 같은 표현식은 런타임에 TypeError를 발생시킵니다.

런타임에 이를 안전하게 지원하려면 라이브러리 작성자는 메타데이터 객체에 __rmatmul__를 구현하는 것이 좋습니다. 이는 왼쪽 피연산자에서 __matmul__을 호출하지 않는 타입(예: NoneType또는 ForwardRef)에 강력한 대체 경로를 제공합니다.

지원되는 왼쪽 피연산자

@ 연산자는 typenb_matrix_multiply를 추가하고, | 합집합 연산자를 지원하는 모든 타이핑 구성 요소(types.GenericAlias, types.UnionType, types.AnnotatedType, typing.TypeVar, typing.ParamSpec, typing.TypeVarTuple, typing.TypeAliasType, typing.ForwardRefsentinel 객체)에 추가합니다.

클래스에 @를 적용하면 타입 메타데이터로 평가되고, 인스턴스에 적용하면 산술 연산을 수행합니다.

예를 들어 int @ Field()AnnotatedType을 생성하는 반면, 42 @ somethingTypeError를 발생시키거나 __rmatmul__에 위임합니다.

마찬가지로 ndarray @ Field()AnnotatedType을 생성하며, ndarray 인스턴스가 행렬 곱셈을 위한 __matmul__을 정의하더라도 그러합니다.

사용자 정의 메타클래스는 타입 표현식에서 @를 피하는 한 __matmul__을 오버로드할 수 있습니다.

근거

Annotated는 타입 메타데이터가 매개변수화된 클래스와 유사해지도록 강제합니다. 후위 연산자는 중첩 없이 동일한 의미를 제공합니다.

기존 @ 연산자를 재사용하면 Python 파서를 변경하지 않아도 됩니다. 연산자의 새로운 의미는 타입 평가로 한정되며, 여기서 T @ MAnnotated[T, M]으로 변환됩니다. 타입 검사기(Mypy, Pyright)도 파서 변경이 필요하지 않으며, 의미 분석 중에 해당 구문을 직접 처리합니다. 자동 마이그레이션을 위한 Ruff 변환 규칙을 프로토타이핑했으며, CPython 프로토타입 테스트를 통해 typerpydantic같은 라이브러리가 수정 없이 계속 작동함을 확인했습니다.

괄호와 장황함

address: (str | None) @Field(...)를 작성하면 네이티브 기호 데코레이터가 없기 때문에 장황해집니다. 프레임워크는 필드를 구성하기 위해 Annotated를 전용 방식으로 활용하지만, 개발자가 의도한 것은 str | None 타입이 아니라 address 필드를 구성하는 것입니다. @ 축약형이 이러한 구조적 한계를 완전히 제거할 수는 없지만, Annotated[str | None, Field(...)]와 비교하면 이 우회 방법의 구문적 부담을 크게 줄입니다.

왜 @ 연산자인가?

메타데이터에 적합한 연산자를 선택하려면 세 가지 고려 사항의 균형을 맞춰야 합니다.

  1. Precedence: |(Union) 및 &(제안된 Intersection)보다 더 강하게 결합되도록 하면 int @ Field() | str과 같은 표현식을 괄호 없이도 올바르게 구문 분석할 수 있습니다. 따라서 |, ^&와 같은 연산자는 제외됩니다.
  2. Ecosystem Compatibility: 새로운 키워드는 생태계 전반의 파서 마이그레이션을 필요로 합니다. Python의 타입 시스템은 타입의 산술 체계로 발전하고 있으므로(예: Union|로 대체), 연산자를 재사용하면 불필요한 변경 없이 이 패턴을 확장할 수 있습니다.
  3. Semantic Clarity: 선택한 구문은 기본 타입에 대해 정립된 직관과 충돌하지 않아야 합니다.

따라서 &보다 더 강하게 결합하는 오버로드 가능한 이항 연산자는 **, *, @, /, //, %, +, -, >><<로 한정됩니다.

+, -, /, //, *, **%와 같은 표준 산술 연산자는 오해를 불러일으킵니다. int + x또는 float / Field()를 읽으면 메타데이터 데코레이션이 아니라 수학적 평가를 강하게 암시합니다.

남은 후보는 <<, >>, @입니다. @를 선택한 이유는 Python에서 데코레이터를 통해 이미 메타데이터와 연관되어 있기 때문입니다. NumPy와 같은 라이브러리에서는 이를 행렬 곱셈에 사용하지만, +/와 같은 연산자만큼 산술 연산에 밀접하게 연결되어 있지는 않습니다.

하위 호환성

상위 10,000개의 PyPI 프로젝트를 분석한 결과 __matmul__또는 __rmatmul__에 대한 메타클래스 오버로드는 0개였습니다. (비교를 위해 설명하면, 이 분석에서는 pgpy (#1,690), dataclass-wizard (#2,205), multimethod (#2,377)와 같은 라이브러리에서 드물게 __or____and__오버로드를 발견했습니다.)

순수 Python으로 구현된 typing._AnnotatedAlias 클래스는 네이티브 C 구현인 types.AnnotatedType로 대체됩니다. typing.Annotated는 사용자 지정 메타클래스를 사용하는 특수 형식이 아니라 이 C 타입을 참조하게 됩니다.

원활한 전환을 보장하기 위해 이 레거시 클래스는 더 이상 사용되지 않는 호환성 shim으로 유지됩니다. isinstance(x, typing._AnnotatedAlias)를 사용하는 코드는 계속 작동하지만 DeprecationWarning을 발생시킵니다. 이 shim은 Python 3.21에서 제거될 예정입니다 (Open Issues 참조).

업데이트해야 하는 코드:

  • type(ann).__name__ == '_AnnotatedAlias'isinstance(ann, types.AnnotatedType)또는 typing.get_origin(ann) is Annotated를 사용하십시오.
  • typing._AnnotatedAlias(origin, metadata)Annotated[origin, *metadata]또는 origin @m1 @m2를 사용하십시오.

typing_extensions를 통한 백포팅: X | Y와 마찬가지로 @ 약식 표기는 메타타입인 type.__matmul__의 변경이 필요하며, 이는 순수 Python에서 패치할 수 없습니다. 이 약식 표기는 Python 3.16 이상에서만 사용할 수 있습니다. 기존 Annotated[X, Y] 구문은 지원되는 모든 버전에서 계속 작동하며, 하위 호환성이 필요한 경우 사용해야 합니다.

보안 영향

직접적인 보안 영향은 없습니다.

가르치는 방법

Python에서 @ 기호는 데코레이터를 통해 이미 메타데이터와 확립된 연관성을 갖고 있습니다. 어노테이션 약식 표기는 이러한 직관을 타입 시스템으로 확장합니다. int @ Field(gt=0)은 “int, Field(gt=0)로 데코레이터가 적용된” 것으로 읽힙니다.

초보자에게 핵심 규칙은 다음과 같습니다. 타입 어노테이션에서 ``@``는 “이 메타데이터와 함께”를 의미합니다. 숙련된 개발자에게 이 개념 모델은 표준 Python 연산자 우선순위에 직접 대응합니다(@|보다 우선순위가 높습니다).

문서와 교육 자료에서는 메타데이터를 적용하는 기본 구문으로 이 약식 표기를 소개해야 합니다. 장황한 typing.Annotated 형식은 주로 라이브러리 작성자나 타입을 동적으로 생성할 때 관련되는 고급 세부 사항으로 다루어야 합니다.

사용 예제

Pydantic 유효성 검사: 이 약식 표기는 데이터 유효성 검사 상황에서 사용할 수 있습니다.:

from pydantic import BaseModel, Field, HttpUrl
from annotated_types import Len

class Project(BaseModel):
    name: str @ Field(title="Project Name") @ Len(1)
    url: HttpUrl @ Field(description="The project homepage")
    stars: int @ Field(ge=0) = 0

FastAPI 의존성 주입: FastAPI에서는 이 약식 표기를 사용하여 복잡한 매개변수 정의를 간소화할 수 있습니다.:

from fastapi import FastAPI, Header, Depends

app = FastAPI()

@app.get("/secure")
async def secure_endpoint(token: str @ Header(description="Auth token")):
    return {"status": "authorized"}

SQLModel 및 데이터베이스 정의: SQLModel은 열 속성을 정의하기 위해 Annotated를 사용합니다. 약식 구문을 사용하면 이러한 정의가 간결해집니다.:

from sqlmodel import SQLModel, Field

class Hero(SQLModel, table=True):
    id: (int | None) @ Field(primary_key=True) = None
    name: str @ Field(index=True)
    secret_name: str
    age: (int | None) @ Field(index=True) = None

테스트 및 형식 검증: Hypothesis와 CrossHair 같은 라이브러리는 annotated-types를 사용하여 테스트 생성을 제한합니다. 이 약식 표기는 테스트 경계를 지정하는 깔끔한 구문을 제공합니다.:

from dataclasses import dataclass
from annotated_types import Ge, Interval
from hypothesis import given

@dataclass
class InventoryItem:
    # A non-negative quantity
    quantity: int @ Ge(0)
    # A price bounded between 1 and 100
    price: float @ Interval(gt=0, le=100)

@given(...)
def test_inventory(item: InventoryItem):
    assert item.price * item.quantity >= 0

생태계 마이그레이션

이 축약형을 여러 주요 타입 지향 프레임워크로 마이그레이션하여 검증했습니다. 테스트가 계속 통과하도록 보장하기 위해 다음의 2단계 접근 방식을 사용했습니다:

  1. 지원 추가: 먼저 라이브러리의 내부 메커니즘을 업데이트하여 @ 구문을 허용했습니다.
  2. 프로젝트 이동: 그런 다음 Annotated의 모든 내부 사용을 @ 연산자로 마이그레이션했습니다.

지원을 추가하는 데 필요한 수정 사항은 다음과 같습니다:

  • FastAPI: LOC 0개(Pydantic에서 상속)
  • Pydantic: LOC 50개
  • SQLAlchemy: LOC 282개
  • cattrs: LOC 155개
  • Hypothesis: LOC 15개
  • Beartype: LOC 12개

하위 호환성을 유지하기 위해 이러한 변경 사항 대부분은 테스트 스위트와 문자열 표현 로직(예: __repr__)에 국한되었습니다. 총계에는 라이브러리의 기본 메타데이터 클래스에 2줄짜리 __rmatmul__메서드를 추가한 작업도 포함됩니다. 이 메서드는 해석할 수 없는 전방 참조와 None @ Metadata를 지원하기 위한 대체 수단으로 작동합니다.

참조 구현

다음 도구에 대한 프로토타입 구현을 사용할 수 있습니다:

Typeshed의 builtins.type에는 타입 검사기를 지원하기 위해 def __matmul__(self, other: Any) -> types.AnnotatedType: ...가 포함되도록 업데이트됩니다.

거부된 아이디어

대안 구문

@를 재사용하는 것에 관한 논의에서 몇 가지 대안이 제시되었습니다:

  • 새로운 중위 연산자: int <@ Field(...)
  • 새로운 소프트 키워드: int annotated Interval(1, 10)
  • 대괄호 구문: x: int {Gt(10), Lt(20)}

이러한 대안에는 합의가 이루어지지 않았습니다. 또한 언어가 나중에 해당 방식을 채택한다면 @ 기호를 기호 데코레이터로도 자연스럽게 확장할 수 있습니다.

__rmatmul__에만 의존

메타데이터 객체가 __rmatmul__을 구현하여(예: 베이스 클래스를 통해) Annotated 타입을 반환하도록 하는 방식에 전적으로 의존하는 것을 명시적으로 거부합니다.:

class Metadata[T = object]:
    def __rmatmul__(self, typ: TypeForm[T], /) -> TypeForm[T]:
        return Annotated[typ, self]

class Le(Metadata[int]):
    ...

이 접근 방식은 두 가지 이유로 거부되었습니다. 첫째, 임의의 우변 객체가 __rmatmul__을 구현하도록 의존하면 타입 표현식 모델이 깨지고, 연산자에 고정된 정적 의미를 할당하기가 복잡해집니다. 이는 |이 작동하는 방식과 일치하지 않으며, 명세에서 정의한 타입 표현식 문법과도 모순됩니다. 둘째, PEP 593은 문자열과 딕셔너리 등 유효한 모든 Python 객체를 메타데이터로 명시적으로 허용합니다. type 메타클래스에 __matmul__을 직접 구현하면 옵트인 베이스 클래스를 사용하지 않아도 되며 일관된 동작을 제공합니다.

매개변수/필드 데코레이터

진정한 매개변수/필드 데코레이터는 일단 거부되었습니다. 기호 수준 데코레이터를 위해 핵심 파서를 수정하면 복잡한 설계 공간이 열리지만, 이 PEP에서는 @연산자의 범위를 타입 표현식으로 한정합니다.

행렬 곱셈으로 인해 @ 피하기

@를 행렬 곱셈과 연관된다는 이유로 피해야 한다는 주장을 받아들이지 않았습니다. 타입 표현식 내에서 Python은 이미 표준 연산자(예: 합집합에 |을, 제네릭에 []를 사용함)를 타이핑에 특화된 의미로 재사용합니다(Why the @ Operator? 참조).

구조적 평가 형식 (Format.TYPE)

초기 초안에서는 @연산자를 구조적으로 평가하고 확인할 수 없는 ForwardRef 인스턴스에 메타데이터를 보존하기 위해 annotationlib에 새로운 Format.TYPE을 추가할 것을 제안했습니다(PEP 749).

이 제안은 거부되었습니다. 프로토타입 통합(beartype, pydantic, fastapi, sqlalchemy, hypothesis)을 통해 기존 생태계가 annotationlib의 현재 도구를 사용하여 @연산자를 처리한다는 사실이 확인되었습니다.

공백 없는 형식 (@annot)

처음에는 함수 데코레이터를 시각적으로 모방하기 위해 공백 없는 축약 형식(예: int @Field)을 고려했습니다. 이는 Black과 Ruff 같은 포매터가 @연산자에 대해 복잡하고 문맥에 의존하는 규칙을 유지하도록 강제하므로 거부되었습니다.

향후 작업

이 제안은 독립적으로 성립하지만, 타입 메타데이터에 @를 도입하면 여러 가지 향후 확장이 가능해집니다.

네이티브 기호 데코레이터

개발자들은 프레임워크에 구애받지 않는 필드 데코레이터를 요청합니다.:

class User(BaseModel):
    @Field(primary_key=True)
    id: int

향후 제안에서는 다음 두 가지 아키텍처 모델 사이를 조정해야 할 가능성이 높습니다.

  • 디스크립터 모델: 데코레이터가 런타임 함수로 작동하여 descriptor를 반환하고, 표준 Python 함수 데코레이터와 유사하게 속성 접근을 적극적으로 가로챕니다.
  • 메타데이터 모델: 필드 구성을 수동적인 기호 메타데이터로 취급하고, 이를 포함하는 클래스가 생성 중에 처리하도록 둡니다.

이 제안은 메타데이터 모델에 부합합니다. 타입 지향 라이브러리는 일반적으로 독립형 디스크립터에 의존하기보다는 클래스 생성 중에 정적 정의를 검사합니다.

@Field(...) id: intid: int @Field(...)와 동일하게 평가됩니다. 이를 통해 기존 프레임워크가 필드 구성을 검사하면서 수정 없이 계속 작동할 수 있습니다. 이 모델에서는 값 공간 데코레이터가 런타임에 객체를 수정하는 반면, 타입 공간 데코레이터는 타입에 메타데이터를 연결합니다.

대상 메타데이터

향후 PEP 746에 대한 확장에서는 어노테이션 대상을 지원할 수 있습니다. 베이스 타입과 명시적인 대상 제약 조건을 교집합하면, 타입 검사기는 메타데이터가 어디에 존재하도록 허용되는지를 검증합니다. 이를 통해 클래스 필드가 아닌 함수 매개변수에 @Column을 배치하는 등의 오용을 완화할 수 있습니다:

참고: 다음 예제에서는 교집합 타입을 위한 ``&`` 연산자가 추가되었다고 가정합니다.

from typing import Target

class Column:
    """Valid only on integers that are fields of a SQLAlchemy Model."""
    __supports_annotated_base__: int & Target.FIELD[SQLAlchemy.Model]

메타데이터를 위한 네이티브 구문을 확립하면 어노테이션 대상과 같은 향후 확장을 위한 구조적 기반이 마련됩니다.

미해결 문제

지원 중단 일정: 비공개 클래스인 typing._AnnotatedAlias는 표준 5년 지원 중단 정책(PEP 387)을 우회할 수 있습니다. 해당 제거를 신속하게 진행해야 합니까?

감사의 말

이 제안을 개선하는 과정에서 피드백과 조언, 도움을 주신 Hugo van Kemenade, Jelle Zijlstra, Eric Traut께 감사드립니다.

참고 자료