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

Python 개선 제안 한국어 번역

PEP 746 – Annotated 메타데이터 타입 검사

Author:
Adrian Garcia Badaracco <adrian at adriangb.com>
Sponsor:
Jelle Zijlstra <jelle.zijlstra at gmail.com>
Discussions-To:
Discourse thread
Status:
Draft
Type:
Standards Track
Topic:
Typing
Created:
20-May-2024
Python-Version:
3.15
Post-History:
20-May-2024

Table of Contents

번역·라이선스 안내

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

초록

이 PEP는 typing.Annotated 타입을 사용하는 메타데이터 타입 검사 메커니즘을 제안합니다. 새로운 __supports_annotated_base__ 프로토콜을 구현하는 메타데이터 객체는 해당 타입에 대해 메타데이터가 유효한지 확인하기 위해 정적 타입 검사기로 타입 검사를 수행합니다.

동기

PEP 593은 타입에 런타임 메타데이터를 첨부하는 방법으로 Annotated를 도입했습니다. 일반적으로 메타데이터는 정적 타입 검사기를 위한 것이 아니지만, 그렇더라도 주어진 타입에 메타데이터가 적합한지 확인할 수 있으면 유용한 경우가 많습니다.

필드에 직렬화 정보를 첨부하기 위해 Annotated를 사용하는 PEP 593의 첫 번째 예를 살펴보십시오.:

class Student(struct2.Packed):
    name: Annotated[str, struct2.ctype("<10s")]

여기서 struct2.ctype("<10s") 메타데이터는 직렬화 라이브러리가 필드를 직렬화하는 데 사용하도록 의도되었습니다. 이러한 라이브러리는 타입의 일부만 직렬화할 수 있으므로, 예를 들어 Annotated[list[str], struct2.ctype("<10s")]와 같이 작성하는 것은 의미가 없습니다. 그러나 타입 시스템에는 이를 강제할 방법이 없습니다. 타입 검사기는 메타데이터를 완전히 무시합니다.

이러한 사용 사례는 pydanticmsgspec와 같은 라이브러리에서 나타납니다. 이 라이브러리들은 필드에 유효성 검사 및 변환 정보를 첨부하기 위해 Annotated를 사용하며, fastapi는 헤더, 쿼리 문자열 또는 의존성 주입에서 추출된 매개변수를 표시하기 위해 Annotated를 사용합니다.

명세

이 PEP는 정적 및 런타임 타입 검사기가 Annotated 메타데이터와 주어진 타입 간의 일관성을 검증하는 데 사용할 수 있는 프로토콜을 도입합니다. 이 프로토콜을 구현하는 객체에는 __supports_annotated_base__라는 속성이 있으며, 이 속성은 주어진 타입에 대해 메타데이터가 유효한지를 지정합니다.:

class Int64:
    __supports_annotated_base__: int

데이터클래스와의 상호 작용을 방지하기 위해 이 속성을 ClassVar로 표시할 수도 있습니다.:

from dataclasses import dataclass
from typing import ClassVar

@dataclass
class Gt:
    value: int
    __supports_annotated_base__: ClassVar[int]

정적 타입 검사기가 Annotated[T, M1, M2, ...] 형태의 타입 표현식을 만나면, M1, M2, ...의 각 메타데이터 요소에 대해 다음 중 하나가 성립하는지 강제해야 합니다.

  • 메타데이터 요소가 __supports_annotated_base__ 속성이 없는 객체로 평가됩니다.
  • 메타데이터 요소가 __supports_annotated_base__ 속성을 가진 객체 M으로 평가되며, TM.__supports_annotated_base__의 타입에 할당 가능합니다.

제네릭 Gt 메타데이터를 지원하려면 다음과 같이 작성할 수 있습니다.:

from typing import Protocol

class SupportsGt[T](Protocol):
    def __gt__(self, __other: T) -> bool:
        ...

class Gt[T]:
    __supports_annotated_base__: ClassVar[SupportsGt[T]]

    def __init__(self, value: T) -> None:
        self.value = value

x1: Annotated[int, Gt(0)] = 1  # OK
x2: Annotated[str, Gt(0)] = 0  # type checker error: str is not assignable to SupportsGt[int]
x3: Annotated[int, Gt(1)] = 0  # OK for static type checkers; runtime type checkers may flag this

하위 호환성

프로토콜을 구현하지 않는 메타데이터는 모든 타입에 대해 유효한 것으로 간주되므로 기존 코드에 호환성을 깨뜨리는 변경 사항은 도입되지 않습니다. 새로운 검사는 이 PEP에서 지정한 프로토콜을 명시적으로 구현하는 메타데이터 객체에만 적용됩니다.

보안 관련 사항

없습니다.

교육 방법

이 프로토콜은 주로 Annotated 메타데이터를 제공하는 라이브러리를 위한 것이며, 해당 라이브러리의 최종 사용자가 직접 프로토콜을 구현해야 할 가능성은 낮습니다. 이 프로토콜은 typing.Annotated의 문서와 타이핑 명세에서 언급해야 합니다.

참조 구현

아직 없습니다.

거부된 아이디어

제네릭 클래스 대신 타입 변수 도입

특수 타입 변수 AnnotatedT = TypeVar("AnnotatedT")를 사용하여 Annotated의 내부 타입인 타입 T를 나타내는 방안을 고려했습니다. 메타데이터는 이 타입 변수를 기준으로 타입 검사를 받게 됩니다. 그러나 이렇게 하려면 현재는 권장되지 않는 기능인 기존 타입 변수 구문(PEP 695 이전)을 사용해야 합니다. 또한 이는 나머지 타입 시스템과 잘 맞지 않는 특이한 방식으로 타입 변수를 사용하게 됩니다.

모든 메타데이터 객체가 상속해야 하는 새로운 타입을 typing.py에 도입

이 PEP의 이전 버전에서는 메타데이터 객체가 상속하는 새로운 제네릭 베이스 클래스 TypedMetadata[U]를 추가하자고 제안했습니다. 메타데이터 객체가 TypedMetadata[U]의 서브클래스라면, 타입 검사기는 어노테이션의 기본 타입을 U에 할당할 수 있는지 검사합니다. 그러나 이 메커니즘은 언어의 나머지 부분과 잘 통합되지 않습니다. Python은 일반적으로 마커 베이스 클래스를 사용하지 않습니다. 또한 현재 제안보다 유연성이 떨어집니다. 오버로드를 허용하지 않으며, 메타데이터 객체가 새로운 베이스 클래스를 추가해야 하므로 런타임 구현이 더 복잡해질 수 있습니다.

__supports_annotated_base__에 속성 대신 메서드 사용

프로토콜에 속성 대신 메서드를 사용하는 방안을 고려했습니다. 이렇게 하면 이 메서드를 런타임에 사용하여 메타데이터의 유효성을 검사하고, 오버로드를 지원하거나 불리언 리터럴을 반환할 수 있습니다. 그러나 메서드를 사용하면 구현에 상용구 코드가 추가되며, 런타임 사용 사례의 가치나 오버로드 및 불리언 리터럴 반환과 관련된 더 복잡한 시나리오의 가치가 명확하지 않았습니다.

감사의 말

프로토콜을 사용하고 Pyright에서 잠정적 지원을 구현하자는 아이디어를 제안해 주신 Eric Traut에게 감사드립니다. 이 PEP를 후원해 주신 Jelle Zijlstra에게 감사드립니다.