Movatterモバイル変換


[0]ホーム

URL:


Following system colour schemeSelected dark colour schemeSelected light colour scheme

Python Enhancement Proposals

PEP 604 – Allow writing union types asX|Y

Author:
Philippe PRADOS <python at prados.fr>, Maggie Moss <maggiebmoss at gmail.com>
Sponsor:
Chris Angelico <rosuav at gmail.com>
BDFL-Delegate:
Guido van Rossum <guido at python.org>
Discussions-To:
Typing-SIG list
Status:
Final
Type:
Standards Track
Topic:
Typing
Created:
28-Aug-2019
Python-Version:
3.10
Post-History:
28-Aug-2019, 05-Aug-2020

Table of Contents

Important

This PEP is a historical document. The up-to-date, canonical documentation can now be found atUnion Type.

×

SeePEP 1 for how to propose changes.

Abstract

This PEP proposes overloading the| operator on types to allowwritingUnion[X,Y] asX|Y, and allows it to appear inisinstance andissubclass calls.

Motivation

PEP 484 andPEP 526 propose a generic syntax to add typing to variables,parameters and function returns.PEP 585 proposes toexposeparameters to generics at runtime.Mypy[1] accepts a syntax which looks like:

annotation: name_typename_type: NAME (args)?args: '[' paramslist ']'paramslist: annotation (',' annotation)* [',']
  • To describe a disjunction (union type), the user must useUnion[X,Y].

The verbosity of this syntax does not help with type adoption.

Proposal

Inspired by Scala[2] and Pike[3], this proposal adds operatortype.__or__(). With this new operator, it is possible to writeint|str instead ofUnion[int,str]. In addition toannotations, the result of this expression would then be valid inisinstance() andissubclass():

isinstance(5,int|str)issubclass(bool,int|float)

We will also be able to writet|None orNone|t instead ofOptional[t]:

isinstance(None,int|None)isinstance(42,None|int)

Specification

The new union syntax should be accepted for function, variable and parameter annotations.

Simplified Syntax

# Instead of# def f(list: List[Union[int, str]], param: Optional[int]) -> Union[float, str]deff(list:List[int|str],param:int|None)->float|str:passf([1,"abc"],None)# Instead of typing.List[typing.Union[str, int]]typing.List[str|int]list[str|int]# Instead of typing.Dict[str, typing.Union[int, float]]typing.Dict[str,int|float]dict[str,int|float]

The existingtyping.Union and| syntax should be equivalent.

int|str==typing.Union[int,str]typing.Union[int,int]==intint|int==int

The order of the items in the Union should not matter for equality.

(int|str)==(str|int)(int|str|float)==typing.Union[str,float,int]

Optional values should be equivalent to the new union syntax

None|t==typing.Optional[t]

A new Union.__repr__() method should be implemented.

str(int|list[str])# int | list[str]str(int|int)# int

isinstance and issubclass

The new syntax should be accepted for calls toisinstance andissubclass as long as the Union items are valid arguments toisinstance andissubclass themselves.

# validisinstance("",int|str)# invalidisinstance(2,list[int])# TypeError: isinstance() argument 2 cannot be a parameterized genericisinstance(1,int|list[int])# validissubclass(bool,int|float)# invalidissubclass(bool,bool|list[int])

Incompatible changes

In some situations, some exceptions will not be raised as expected.

If a metaclass implements the__or__ operator, it will override this:

>>>classM(type):...def__or__(self,other):return"Hello"...>>>classC(metaclass=M):pass...>>>C|int'Hello'>>>int|Ctyping.Union[int, __main__.C]>>>Union[C,int]typing.Union[__main__.C, int]

Objections and responses

For more details about discussions, see links below:

1. Add a new operator forUnion[type1,type2]?

PROS:

  • This syntax can be more readable, and is similar to other languages (Scala, …)
  • At runtime,int|str might return a simple object in 3.10, rather than everything thatyou’d need to grab from importingtyping

CONS:

  • Adding this operator introduces a dependency betweentyping andbuiltins
  • Breaks the backport (in thattyping can easily be backported but coretypes can’t)
  • If Python itself doesn’t have to be changed, we’d still need to implement it in mypy, Pyre, PyCharm,Pytype, and who knows what else (it’s a minor change see “Reference Implementation”)

2. Change only PEP 484 (Type hints) to accept the syntaxtype1|type2 ?

PEP 563 (Postponed Evaluation of Annotations) is enough to accept this proposition,if we accept to not be compatible with the dynamic evaluation of annotations (eval()).

>>>from__future__importannotations>>>deffoo()->int|str:pass...>>>eval(foo.__annotations__['return'])Traceback (most recent call last):  File"<stdin>", line1, in<module>  File"<string>", line1, in<module>TypeError:unsupported operand type(s) for |: 'type' and 'type'

3. Extendisinstance() andissubclass() to acceptUnion ?

isinstance(x,str|int)==>"is x an instance of str or int"

PROS:

  • If they were permitted, then instance checking could use an extremely clean-looking notation

CONS:

  • Must migrate all of thetyping module inbuiltin

Reference Implementation

A new built-inUnion type must be implemented to hold the returnvalue oft1|t2, and it must be supported byisinstance() andissubclass(). This type can be placed in thetypes module.Interoperability betweentypes.Union andtyping.Union must beprovided.

Once the Python language is extended, mypy[1] and other type checkers willneed to be updated to accept this new syntax.

References

[1] (1,2)
mypyhttp://mypy-lang.org/
[2]
Scala Union Typeshttps://dotty.epfl.ch/docs/reference/new-types/union-types.html
[3]
Pikehttp://pike.lysator.liu.se/docs/man/chapter_3.html#3.5

Copyright

This document is placed in the public domain or under the CC0-1.0-Universal license, whichever is more permissive.


Source:https://github.com/python/peps/blob/main/peps/pep-0604.rst

Last modified:2024-02-16 17:06:07 GMT


[8]ページ先頭

©2009-2025 Movatter.jp