Important
This PEP is a historical document: seeType aliases andtyping.TypeAlias for up-to-date specs and documentation. Canonical typing specs are maintained at thetyping specs site; runtime typing behaviour is described in the CPython documentation.
×
See thetyping specification update process for how to propose changes to the typing spec.
Type aliases are user-specified types which may be as complex as any type hint,and are specified with a simple variable assignment on a module top level.
This PEP formalizes a way to explicitly declare an assignment as a type alias.
Type aliases are declared as top level variable assignments.InPEP 484,the distinction between a valid type alias and a global variable was implicitlydetermined: if a top level assignment is unannotated, and the assigned value isa valid type, then the name being assigned to is a valid type alias. Otherwise,that name is simply a global value that cannot be used as a type hint.
These implicit type alias declaration rules create confusion when type aliasesinvolve forward references, invalid types, or violate other restrictionsenforced on type alias declaration. Because the distinction between anunannotated value and a type alias is implicit, ambiguous or incorrect typealias declarations implicitly default to a valid value assignment. This createsexpressions that are impossible to express as type aliases and punts errordiagnosis of malformed type aliases downstream.
The following examples each include an illustration of some of the suboptimalor confusing behaviors resulting from existing implicit alias declarations.We also introduce explicit aliases of the formatTypeName:TypeAlias=Expressionhere for the sake of comparison, but the syntax is discussed in further detailin later sections.
MyType="ClassName"deffoo()->MyType:...
This code snippet should not error so long asClassName is definedlater on. However, a type checker is forced to assume that MyType is a valueassignment rather than a type alias, and therefore may throw spurious errorsthat (1)MyType is an unannotated global string, and (2)MyTypecannot be used as a return annotation because it is not a valid type.
MyType:TypeAlias="ClassName"deffoo()->MyType:...
Explicit aliases remove ambiguity so neither of the above errors will bethrown. Additionally, if something is wrong withClassName(i.e., it’s not actually defined later), the type checker can throw an error.
MyType1=InvalidTypeMyType2=MyGeneric(int)# i.e., intention was MyGeneric[int]
A type checker should warn on this code snippet thatInvalidType is nota valid type, and therefore cannot be used to annotate an expression or toconstruct a type alias. Instead, type checkers are forced to throw spuriouserrors that (1)MyType is a global expression missing an annotation,and (2)MyType is not a valid type in all usages ofMyTypeacross the codebase.
MyType1:TypeAlias=InvalidTypeMyType2:TypeAlias=MyGeneric(int)
With explicit aliases, the type checker has enough information to error on theactual definition of the bad type alias, and explain why: thatMyGeneric(int)andInvalidType are not valid types. When the value expression is no longerevaluated as a global value, unactionable type errors on all usages ofMyTypeacross the codebase can be suppressed.
classFoo:x=ClassNamey:TypeAlias=ClassNamez:Type[ClassName]=ClassName
Type aliases are valid within class scope, both implicitly (x) andexplicitly (y). If the line should be interpreted as a classvariable, it must be explicitly annotated (z).
x=ClassNamedeffoo()->None:x=ClassName
The outerx is a valid type alias, but type checkers must error if theinnerx is ever used as a type because type aliases cannot be definedinside of a function.This is confusing because the alias declaration rule is not explicit, and becausea type error will not be thrown on the location of the inner type alias declarationbut rather on every one of its subsequent use cases.
x:TypeAlias=ClassNamedeffoo()->None:x=ClassNamedefbar()->None:x:TypeAlias=ClassName
With explicit aliases, the outer assignment is still a valid type variable.Insidefoo, the inner assignment should be interpreted asx:Type[ClassName].Insidebar, the type checker should raise a clear error, communicatingto the author that type aliases cannot be defined inside a function.
The explicit alias declaration syntax clearly differentiates between the threepossible kinds of assignments: typed global expressions, untyped globalexpressions, and type aliases. This avoids the existence of assignments thatbreak type checking when an annotation is added, and avoids classifying thenature of the assignment based on the type of the value.
Implicit syntax (pre-existing):
x=1# untyped global expressionx:int=1# typed global expressionx=int# type aliasx:Type[int]=int# typed global expression
Explicit syntax:
x=1# untyped global expressionx:int=1# typed global expressionx=int# untyped global expression (see note below)x:Type[int]=int# typed global expressionx:TypeAlias=int# type aliasx:TypeAlias="MyClass"# type alias
Note: The examples above illustrate implicit and explicit alias declarations inisolation. For the sake of backwards compatibility, type checkers should supportboth simultaneously, meaning an untyped global expressionx=int willstill be considered a valid type alias.
Explicit aliases provide an alternative way to declare type aliases, but allpre-existing code and old alias declarations will work as before.
ThePyre type checker supports explicit typealias declarations.
Some alternative syntaxes were considered for explicit aliases:
MyType:TypeAlias[int]
This looks a lot like an uninitialized variable.
MyType=TypeAlias[int]
Along with the option above, this format potentially adds confusion aroundwhat the runtime value ofMyType is.
In comparison, the chosen syntax optionMyType:TypeAlias=int isappealing because it still sticks with theMyType=int assignmentsyntax, and adds some information for the type checker purely as an annotation.
TypeAlias inside class scopeThis document is placed in the public domain or under theCC0-1.0-Universal license, whichever is more permissive.
Source:https://github.com/python/peps/blob/main/peps/pep-0613.rst
Last modified:2024-06-11 22:12:09 GMT