PEP 747 – Typisierungen von Typ-Formen
- Autor:
- David Foster <david at dafoster.net>, Eric Traut <erictr at microsoft.com>
- Sponsor:
- Jelle Zijlstra <jelle.zijlstra at gmail.com>
- Discussions-To:
- Discourse thread
- Status:
- Entwurf
- Typ:
- Standards Track
- Thema:
- Typisierung
- Erstellt:
- 27-Mai-2024
- Python-Version:
- 3.15
- Post-History:
- 19-Apr-2024, 04-May-2024, 17-Jun-2024
Zusammenfassung
Typausdrücke bieten eine standardisierte Methode zur Angabe von Typen im Python-Typsystem. Wenn ein Typausdruck zur Laufzeit ausgewertet wird, kodiert das resultierende *Typ-Form-Objekt* die im Typausdruck bereitgestellten Informationen. Dies ermöglicht eine Vielzahl von Anwendungsfällen, darunter Laufzeittyp-Überprüfung, Introspektion und Metaprogrammierung.
Solche Anwendungsfälle haben sich verbreitet, aber derzeit gibt es keine Möglichkeit, Funktionen, die Typ-Form-Objekte akzeptieren, korrekt zu typisieren. Entwickler sind gezwungen, einen übermäßig breiten Typ wie object zu verwenden, was einige Anwendungsfälle unmöglich macht und die Typsicherheit im Allgemeinen verringert. Dieses PEP adressiert diese Einschränkung durch die Einführung einer neuen Sonderform typing.TypeForm.
Dieses PEP ändert nichts an der Python-Grammatik. Die korrekte Verwendung von TypeForm soll nur von Typ-Checkern erzwungen werden, nicht von der Python-Laufzeitumgebung.
Motivation
Eine Funktion, die mit Typ-Form-Objekten arbeitet, muss verstehen, wie Typdetails in diesen Objekten kodiert sind. Zum Beispiel sind int | str, "int | str", list[int] und MyTypeAlias alles gültige Typausdrücke, und sie werten zu Instanzen von types.UnionType, builtins.str, types.GenericAlias und typing.TypeAliasType aus, jeweils entsprechend.
Derzeit gibt es keine Möglichkeit, einem Typ-Checker anzuzeigen, dass eine Funktion Typ-Form-Objekte akzeptiert und weiß, wie man mit ihnen umgeht. TypeForm adressiert diese Einschränkung. Hier ist zum Beispiel eine Funktion, die prüft, ob ein Wert einem bestimmten Typ zuweisbar ist, und None zurückgibt, wenn dies nicht der Fall ist.
def trycast[T](typx: TypeForm[T], value: object) -> T | None: ...
Die Verwendung von TypeForm und der Typvariable T beschreibt eine Beziehung zwischen der an den Parameter typx übergebenen Typ-Form und dem Rückgabetyp der Funktion.
TypeForm kann auch mit TypeIs verwendet werden, um benutzerdefinierte Typ-Verengungsverhalten zu definieren.
def isassignable[T](value: object, typx: TypeForm[T]) -> TypeIs[T]: ...
request_json: object = ...
if isassignable(request_json, MyTypedDict):
assert_type(request_json, MyTypedDict) # Type of variable is narrowed
Die Funktion `isassignable` implementiert so etwas wie eine erweiterte `isinstance`-Prüfung. Dies ist nützlich, um zu validieren, ob ein aus JSON dekodierter Wert einer bestimmten Struktur verschachtelter `TypedDict`s, Listen, Unionen, `Literal`s oder jeder anderen Typ-Form entspricht, die mit einem Typausdruck beschrieben werden kann. Diese Art von Prüfung wurde in PEP 589 angedeutet, konnte aber ohne TypeForm nicht implementiert werden.
Warum nicht type[C]?
Man könnte denken, dass type[C] für diese Anwendungsfälle ausreicht. Jedoch sind nur Klassenobjekte (Instanzen der Klasse builtins.type) zu type[C] zuweisbar. Viele Typ-Form-Objekte erfüllen diese Anforderung nicht.
def trycast[T](typx: type[T], value: object) -> T | None: ...
trycast(str, 'hi') # OK
trycast(Literal['hi'], 'hi') # Type violation
trycast(str | None, 'hi') # Type violation
trycast(MyProtocolClass, obj) # Type violation
TypeForm Anwendungsfälle
Eine Umfrage unter Python-Bibliotheken zeigt mehrere Kategorien von Funktionen, die von TypeForm profitieren würden.
- Zuweisbarkeitsprüfer
- Bestimmt, ob ein Wert einem angegebenen Typ zuweisbar ist.
- Muster 1:
def is_assignable[T](value: object, typx: TypeForm[T]) -> TypeIs[T] - Muster 2:
def is_match[T](value: object, typx: TypeForm[T]) -> TypeGuard[T] - Beispiele: beartype.is_bearable, trycast.isassignable, typeguard.check_type, xdsl.isa
- Konverter
- Wenn ein Wert einem angegebenen Typ zuweisbar (oder konvertierbar) ist, gibt ein *Konverter* den Wert, verengt auf (oder konvertiert zu) diesen Typ, zurück. Andernfalls wird eine Ausnahme ausgelöst.
- Muster 1
def convert[T](value: object, typx: TypeForm[T]) -> T
- Muster 2
class Converter[T]: def __init__(self, typx: TypeForm[T]) -> None: ... def convert(self, value: object) -> T: ...
- Beispiele: pydantic.TypeAdapter(T).validate_python, mashumaro.JSONDecoder(T).decode
- Definitonen von typisierten Feldern
- Muster
class Field[T]: value_type: TypeForm[T]
- Beispiele: attrs.make_class, dataclasses.make_dataclass [3], openapify
- Muster
Die Umfrage identifizierte auch einige Introspektionsfunktionen, die Laufzeit-Typ-Formen als Eingabe akzeptieren. Heute sind diese Funktionen mit object typisiert.
- Allgemeine Introspektionsoperationen
- Muster:
def get_annotation_info(typx: object) -> object - Beispiele: typing.{get_origin, get_args}, typing_inspect.{is_*_type, get_origin, get_parameters}
- Muster:
Diese Funktionen akzeptieren Werte, die aus beliebigen Annotationsausdrücken ausgewertet wurden, nicht nur Typausdrücke, daher können sie nicht auf die Verwendung von TypeForm geändert werden.
Spezifikation
Wenn ein Typausdruck zur Laufzeit ausgewertet wird, ist der resultierende Wert ein *Typ-Form*-Objekt. Dieser Wert kodiert die im Typausdruck bereitgestellten Informationen und repräsentiert den durch diesen Typausdruck beschriebenen Typ.
TypeForm ist eine Sonderform, die, wenn sie in einem Typausdruck verwendet wird, eine Menge von Typ-Form-Objekten beschreibt. Sie akzeptiert ein einzelnes Typargument, das ein gültiger Typausdruck sein muss. TypeForm[T] beschreibt die Menge aller Typ-Form-Objekte, die den Typ T oder Typen, die zuweisbar zu T sind, repräsentieren. Zum Beispiel beschreibt TypeForm[str | None] die Menge aller Typ-Form-Objekte, die einen Typ repräsentieren, der zu str | None zuweisbar ist.
ok1: TypeForm[str | None] = str | None # OK
ok2: TypeForm[str | None] = str # OK
ok3: TypeForm[str | None] = None # OK
ok4: TypeForm[str | None] = Literal[None] # OK
ok5: TypeForm[str | None] = Optional[str] # OK
ok6: TypeForm[str | None] = "str | None" # OK
ok7: TypeForm[str | None] = Any # OK
err1: TypeForm[str | None] = str | int # Error
err2: TypeForm[str | None] = list[str | None] # Error
Nach derselben Definition beschreibt TypeForm[object] ein Typ-Form-Objekt, das den Typ object oder jeden Typ, der zu object zuweisbar ist, repräsentiert. Da alle Typen im Python-Typsystem zu object zuweisbar sind, beschreibt TypeForm[object] die Menge aller Typ-Form-Objekte, die aus allen gültigen Typausdrücken ausgewertet wurden.
TypeForm[Any] beschreibt einen `TypeForm`-Typ, dessen Typargument nicht statisch bekannt ist, aber ein gültiges Typ-Form-Objekt ist. Er ist somit sowohl zu als auch von jedem anderen `TypeForm`-Typ zuweisbar (da `Any` sowohl zu als auch von jedem Typ zuweisbar ist).
Der Typausdruck TypeForm, ohne Typargument, ist äquivalent zu TypeForm[Any].
Implizite TypeForm Auswertung
Wenn ein statischer Typ-Checker auf einen gültigen Typausdruck stößt, sollte der ausgewertete Typ dieses Ausdrucks zu TypeForm[T] zuweisbar sein, wenn der von ihm beschriebene Typ zu T zuweisbar ist.
Wenn ein statischer Typ-Checker beispielsweise auf den Ausdruck str | None stößt, kann er seinen Typ normalerweise als UnionType auswerten, da er einen Laufzeitwert erzeugt, der eine Instanz von types.UnionType ist. Da dieser Ausdruck jedoch ein gültiger Typausdruck ist, ist er auch zuweisbar zum Typ TypeForm[str | None].
v1_actual: UnionType = str | None # OK
v1_type_form: TypeForm[str | None] = str | None # OK
v2_actual: type = list[int] # OK
v2_type_form: TypeForm = list[int] # OK
Die Sonderform `Annotated` ist in Typausdrücken erlaubt, daher kann sie auch in einem Ausdruck vorkommen, der zu `TypeForm` zuweisbar ist. Im Einklang mit den Regeln der `typing`-Spezifikation für `Annotated` kann ein statischer Typ-Checker wählen, Metadaten von `Annotated` zu ignorieren, die er nicht versteht.
v3: TypeForm[int | str] = Annotated[int | str, "metadata"] # OK
v4: TypeForm[Annotated[int | str, "metadata"]] = int | str # OK
Ein Zeichenketten-Literal-Ausdruck, der einen gültigen Typausdruck enthält, sollte ebenfalls zu `TypeForm` zuweisbar sein.
v5: TypeForm[set[str]] = "set[str]" # OK
Gültige Typausdrücke
Die `typing`-Spezifikation definiert syntaktische Regeln für Typausdrücke in Form einer formalen Grammatik. Semantische Regeln werden als Kommentare zusammen mit der Grammatikdefinition angegeben. Kontextuelle Anforderungen werden in der gesamten `typing`-Spezifikation in Abschnitten detailliert, die Konzepte diskutieren, die innerhalb von Typausdrücken vorkommen. Beispielsweise kann die Sonderform `Self` nur innerhalb einer Klasse in einem Typausdruck verwendet werden, und eine Typvariable kann nur dann innerhalb eines Typausdrucks verwendet werden, wenn sie einem gültigen Gültigkeitsbereich zugeordnet ist.
Ein gültiger Typausdruck ist ein Ausdruck, der allen syntaktischen, semantischen und kontextuellen Regeln für einen Typausdruck folgt.
Ausdrücke, die keine gültigen Typausdrücke sind, sollten nicht zu einem `TypeForm`-Typ ausgewertet werden.
bad1: TypeForm = tuple() # Error: Call expression not allowed in type expression
bad2: TypeForm = (1, 2) # Error: Tuple expression not allowed in type expression
bad3: TypeForm = 1 # Non-class object not allowed in type expression
bad4: TypeForm = Self # Error: Self not allowed outside of a class
bad5: TypeForm = Literal[var] # Error: Variable not allowed in type expression
bad6: TypeForm = Literal[f""] # Error: f-strings not allowed in type expression
bad7: TypeForm = ClassVar[int] # Error: ClassVar not allowed in type expression
bad8: TypeForm = Required[int] # Error: Required not allowed in type expression
bad9: TypeForm = Final[int] # Error: Final not allowed in type expression
bad10: TypeForm = Unpack[Ts] # Error: Unpack not allowed in this context
bad11: TypeForm = Optional # Error: Invalid use of Optional special form
bad12: TypeForm = T # Error if T is an out-of-scope TypeVar
bad13: TypeForm = "int + str" # Error: invalid quoted type expression
Explizite TypeForm Auswertung
TypeForm fungiert auch als Funktion, die mit einem einzigen Argument aufgerufen werden kann. Typ-Checker sollten validieren, dass dieses Argument ein gültiger Typausdruck ist.
x1 = TypeForm(str | None)
reveal_type(v1) # Revealed type is "TypeForm[str | None]"
x2 = TypeForm("list[int]")
revealed_type(v2) # Revealed type is "TypeForm[list[int]]"
x3 = TypeForm('type(1)') # Error: invalid type expression
Zur Laufzeit gibt die aufrufbare Funktion `TypeForm(...)` einfach den ihr übergebenen Wert zurück.
Diese explizite Syntax dient zwei Zwecken. Erstens dokumentiert sie die Absicht des Entwicklers, den Wert als Typ-Form-Objekt zu verwenden. Zweitens validieren statische Typ-Checker, dass alle Regeln für Typausdrücke eingehalten werden.
x4 = type(1) # No error, evaluates to "type[int]"
x5 = TypeForm(type(1)) # Error: call not allowed in type expression
Zuweisbarkeit
TypeForm hat einen einzigen Typparameter, der kovariant ist. Das bedeutet, TypeForm[B] ist zu `TypeForm[A]` zuweisbar, wenn `B` zu `A` zuweisbar ist.
def get_type_form() -> TypeForm[int]: ...
t1: TypeForm[int | str] = get_type_form() # OK
t2: TypeForm[str] = get_type_form() # Error
type[T] ist eine Unterklasse von TypeForm[T], was bedeutet, dass type[B] zu `TypeForm[A]` zuweisbar ist, wenn `B` zu `A` zuweisbar ist.
def get_type() -> type[int]: ...
t3: TypeForm[int | str] = get_type() # OK
t4: TypeForm[str] = get_type() # Error
TypeForm ist eine Unterklasse von object und es wird davon ausgegangen, dass es alle Attribute und Methoden von object hat.
Abwärtskompatibilität
Dieses PEP klärt das Verhalten von statischen Typ-Checkern bei der Auswertung von Typausdrücken in "Wertausdrucks"-Kontexten (d. h. Kontexten, in denen Typausdrücke nicht durch die `typing`-Spezifikation vorgeschrieben sind). In Abwesenheit einer `TypeForm`-Typannotation bleiben bestehende Typ-Auswertungsverhalten bestehen, sodass keine Rückwärtskompatibilitätsprobleme erwartet werden. Wenn beispielsweise ein statischer Typ-Checker zuvor den Typ des Ausdrucks str | None als UnionType ausgewertet hat, wird dies auch weiterhin der Fall sein, es sei denn, dieser Ausdruck wird einer Variablen oder einem Parameter zugewiesen, dessen Typ als TypeForm annotiert ist.
Wie man das lehrt
Typausdrücke werden in Annotationen verwendet, um zu beschreiben, welche Werte von Funktionsparametern akzeptiert, von einer Funktion zurückgegeben oder in einer Variablen gespeichert werden.
parameter type return type
| |
v v
def plus(n1: int, n2: int) -> int:
sum: int = n1 + n2
^
|
variable type
return sum
Typausdrücke werten zur Laufzeit zu gültigen *Typ-Form*-Objekten aus und können wie jede andere Daten in einem Programm Variablen zugewiesen und manipuliert werden.
a variable a type expression
| |
v v
int_type_form: TypeForm = int | None
^
|
the type of a type form object
TypeForm[] ist die Schreibweise für den Typ eines *Typ-Form*-Objekts, das eine Laufzeitrepräsentation eines Typs ist.
TypeForm ist ähnlich wie type, aber type ist nur mit **Klassenobjekten** wie int, str, list oder MyClass kompatibel. TypeForm unterstützt jede Typ-Form, die mit einem gültigen Typausdruck ausgedrückt werden kann, einschließlich solcher mit Klammern (list[int]), Unionsoperatoren (int | None) und Sonderformen (Any, LiteralString, Never usw.).
Die meisten Programmierer werden nicht *ihre eigenen* Funktionen definieren, die einen TypeForm-Parameter akzeptieren oder einen TypeForm-Wert zurückgeben. Es ist üblicher, ein Typ-Form-Objekt an eine Bibliotheksfunktion zu übergeben, die weiß, wie solche Objekte dekodiert und verwendet werden.
Zum Beispiel kann die Funktion `isassignable` in der Bibliothek `trycast` wie die eingebaute Funktion `isinstance` von Python verwendet werden, um zu prüfen, ob ein Wert der Struktur eines bestimmten Typs entspricht. `isassignable` akzeptiert *jedes* Typ-Form-Objekt als Eingabe.
- Ja
from trycast import isassignable if isassignable(some_object, MyTypedDict): # OK: MyTypedDict is a TypeForm[] ...
- Nein
if isinstance(some_object, MyTypedDict): # ERROR: MyTypedDict is not a type[] ...
Fortgeschrittene Beispiele
Wenn Sie Ihren eigenen Laufzeit-Typ-Checker oder eine Funktion schreiben möchten, die Typ-Form-Objekte zur Laufzeit als Werte manipuliert, bietet dieser Abschnitt Beispiele dafür, wie eine solche Funktion TypeForm verwenden kann.
Introspektion von Typ-Form-Objekten
Funktionen wie typing.get_origin und typing.get_args können verwendet werden, um Komponenten einiger Typ-Form-Objekte zu extrahieren.
import typing
from typing import TypeForm, cast
def strip_annotated_metadata[T](typx: TypeForm[T]) -> TypeForm[T]:
if typing.get_origin(typx) is typing.Annotated:
typx = cast(TypeForm[T], typing.get_args(typx)[0])
return typx
isinstance und is können auch verwendet werden, um zwischen verschiedenen Arten von Typ-Form-Objekten zu unterscheiden.
import types
import typing
from typing import TypeForm, cast
def split_union(typx: TypeForm) -> tuple[TypeForm, ...]:
if isinstance(typx, types.UnionType): # X | Y
return cast(tuple[TypeForm, ...], typing.get_args(typx))
if typing.get_origin(typx) is typing.Union: # Union[X, Y]
return cast(tuple[TypeForm, ...], typing.get_args(typx))
if typx in (typing.Never, typing.NoReturn,):
return ()
return (typx,)
Kombination mit einer Typvariable
TypeForm kann durch eine Typvariable parametrisiert werden, die an anderer Stelle innerhalb derselben Funktionsdefinition verwendet wird.
def as_instance[T](typx: TypeForm[T]) -> T | None:
return typx() if isinstance(typx, type) else None
Kombination mit type
Sowohl TypeForm als auch type können innerhalb derselben Funktionsdefinition durch dieselbe Typvariable parametrisiert werden.
def as_type[T](typx: TypeForm[T]) -> type[T] | None:
return typx if isinstance(typx, type) else None
Kombination mit TypeIs und TypeGuard
Eine Typvariable kann auch von einem Rückgabetyp TypeIs oder TypeGuard verwendet werden.
def isassignable[T](value: object, typx: TypeForm[T]) -> TypeIs[T]: ...
count: int | str = ...
if isassignable(count, int):
assert_type(count, int)
else:
assert_type(count, str)
Herausforderungen bei der Akzeptanz aller TypeForms
Eine Funktion, die eine *beliebige* TypeForm als Eingabe nimmt, muss eine Vielzahl möglicher Typ-Form-Objekte unterstützen. Solche Funktionen sind nicht einfach zu schreiben.
- Mit jeder neuen Python-Version werden neue Sonderformen eingeführt, und für jede davon kann eine spezielle Behandlung erforderlich sein.
- Angeführte Annotationen [5] (wie
'list[str]') müssen *geparst* werden (zu etwas wielist[str]). - Das Auflösen von angeführten Vorwärtsreferenzen innerhalb von Typausdrücken erfolgt typischerweise mit
eval(), was schwierig sicher zu verwenden ist. - Rekursive Typen wie
IntTree = list[int | 'IntTree']sind schwer aufzulösen. - Benutzerdefinierte generische Typen (wie Django's
QuerySet[User]) können nicht standardmäßige Verhaltensweisen einführen, die Laufzeitunterstützung erfordern.
Referenzimplementierung
Pyright (Version 1.1.379) bietet eine Referenzimplementierung für TypeForm.
Mypy-Mitwirkende planen auch die Implementierung von Unterstützung für TypeForm.
Eine Referenzimplementierung der Laufzeitkomponente wird im Modul typing_extensions bereitgestellt.
Abgelehnte Ideen
Alternative Namen
Alternative Namen wurden für TypeForm in Betracht gezogen. TypeObject und TypeType wurden als zu generisch erachtet. TypeExpression und TypeExpr wurden ebenfalls in Betracht gezogen, aber diese wurden als verwirrend angesehen, da diese Objekte selbst keine "Ausdrücke" sind, sondern das Ergebnis der Auswertung eines Typausdrucks.
Erweitern von type[C] zur Unterstützung aller Typausdrücke
type wurde entwickelt, um Klassenobjekte zu beschreiben, die Unterklassen der Klasse type sind. Von einem Wert mit dem Typ type wird angenommen, dass er über einen Konstruktoraufruf instanziierbar ist. Die Erweiterung der Bedeutung von type, um beliebige Typ-Form-Objekte darzustellen, würde Probleme mit der Abwärtskompatibilität verursachen und eine Möglichkeit zur Beschreibung der Menge von Werten eliminieren, die auf Unterklassen von type beschränkt sind.
Akzeptieren beliebiger Annotationsausdrücke
Bestimmte Sonderformen fungieren als Typ-Qualifizierer und können in *einigen*, aber nicht in *allen* Annotationskontexten verwendet werden.
Zum Beispiel kann der Typ-Qualifizierer Final als Variablentyp, aber nicht als Parametertyp oder Rückgabetyp verwendet werden.
some_const: Final[str] = ... # OK
def foo(not_reassignable: Final[object]): ... # Error: Final not allowed here
def nonsense() -> Final[object]: ... # Error: Final not allowed here
Mit Ausnahme von Annotated sind Typ-Qualifizierer in Typausdrücken nicht erlaubt. TypeForm ist auf Typausdrücke beschränkt, da seine Zuweisbarkeitsregeln auf den Zuweisbarkeitsregeln für Typen basieren. Es ist unsinnig zu fragen, ob Final[int] zu int zuweisbar ist, da ersteres kein gültiger Typausdruck ist.
Funktionen, die mit Objekten arbeiten möchten, die aus Annotationsausdrücken ausgewertet werden, können solche Eingaben weiterhin als object-Parameter akzeptieren.
Pattern Matching auf Typ-Formen
Es wurde behauptet, dass einige Funktionen möglicherweise mit dem Inneren von Typausdrücken in ihren Signaturen pattern-matchen möchten.
Ein Anwendungsfall ist es, einer Funktion zu erlauben, alle *spezifischen* Arten von Typausdrücken, die sie als Eingabe unterstützt, explizit aufzulisten. Betrachten Sie die folgende mögliche Pattern-Matching-Syntax.
@overload
def checkcast(typx: TypeForm[AT=Annotated[T, *A]], value: str) -> T: ...
@overload
def checkcast(typx: TypeForm[UT=Union[*Ts]], value: str) -> Union[*Ts]: ...
@overload
def checkcast(typx: type[C], value: str) -> C: ...
# ... (more)
Alle in der Praxis beobachteten Funktionen, die konzeptionell Typ-Form-Objekte akzeptieren, versuchen im Allgemeinen, *alle* Arten von Typausdrücken zu unterstützen, daher scheint es nicht wertvoll zu sein, eine bestimmte Teilmenge aufzulisten.
Darüber hinaus ist die obige Syntax nicht präzise genug, um die Eingabebeschränkungen für eine typische Funktion in der Praxis vollständig zu beschreiben. Viele Funktionen unterstützen beispielsweise keine Typausdrücke mit angeführten Unterausdrücken wie list['Movie'].
Ein zweiter Anwendungsfall für Pattern Matching ist es, ein `Annotated`-Form explizit abzugleichen, um das innere Typargument zu extrahieren und beliebige Metadaten zu entfernen.
def checkcast(
typx: TypeForm[T] | TypeForm[AT=Annotated[T, *A]],
value: object
) -> T:
Jedoch wird `Annotated[T, metadata]` von statischen Typ-Checkern bereits als äquivalent zu `T` behandelt. Es gibt keinen zusätzlichen Wert, dies explizit zu machen. Das obige Beispiel könnte einfacher als das Äquivalent geschrieben werden.
def checkcast(typx: TypeForm[T], value: object) -> T:
Danksagungen
- David Foster entwarf die erste Version dieses PEP, entwarf die mypy-Implementierung davon und begleitete es durch den PEP-Prozess.
- Eric Traut lieferte während des gesamten Designprozesses unzählige Rückmeldungen, entwarf ein wichtiges Update des ursprünglichen PEP-Textes und entwarf die pyright-Implementierung davon.
- Jelle Zijlstra lieferte Rückmeldungen, insbesondere zu frühen Entwürfen des PEP, und entwarf die `typing_extensions`-Implementierung der Sonderform `TypeExpr`.
- Carl Meyer und Mehdi Drissi lieferten wertvolle Rückmeldungen, insbesondere zur Frage, ob `type` zu `TypeForm` zugewiesen werden soll oder nicht.
- Cecil Curry (leycec) lieferte Rückmeldungen aus der Perspektive von Laufzeit-Typ-Checkern und experimentierte mit der sich in Entwicklung befindlichen Sonderform `TypeForm` in einem realen Laufzeit-Typ-Checker (beartype).
- Jukka Lehtosalo lieferte Rückmeldungen zur mypy-Implementierung von TypeForm und half dabei, den Prüfalgorithmus schneller laufen zu lassen und weniger Speicher zu verbrauchen.
- Michael H (mikeshardmind) schlug Syntaxideen für das Abgleichen spezifischer Arten von Typ-Formen vor.
- Paul Moore setzte sich für mehrere Änderungen am PEP ein, um ihn für Typ-Neulinge zugänglicher zu machen.
- Tin Tvrtković (Tinche) und Salvo ‘LtWorf’ Tomaselli lieferten zu verschiedenen Zeiten positives Feedback aus der breiteren Community und unterstützten, dass das PEP nützlich sein würde.
Fußnoten
Urheberrecht
Dieses Dokument wird in die Public Domain oder unter die CC0-1.0-Universal-Lizenz gestellt, je nachdem, welche Lizenz permissiver ist.
Quelle: https://github.com/python/peps/blob/main/peps/pep-0747.rst
Zuletzt geändert: 2025-07-22 01:46:04 GMT