PEP 604: I've been asked to take over as PEP-Delegate (#1538)
Here I'm also retargeting this to Python 3.10 and proposing various small changes to clarify the PEP. In addition, we have a new reference implementation in the works.
This commit is contained in:
parent
b1c63f8f00
commit
fede4ec838
76
pep-0604.rst
76
pep-0604.rst
|
@ -1,50 +1,61 @@
|
|||
PEP: 604
|
||||
Title: Complementary syntax for ``Union[]``
|
||||
Title: Allow writing union types as ``X | Y``
|
||||
Author: Philippe PRADOS <python@prados.fr>
|
||||
Sponsor: Chris Angelico <rosuav@gmail.com>
|
||||
BDFL-Delegate: Ivan Levkivskyi <levkivskyi@gmail.com>
|
||||
BDFL-Delegate: Guido van Rossum <guido@python.org>
|
||||
Status: Draft
|
||||
Type: Standards Track
|
||||
Content-Type: text/x-rst
|
||||
Created: 28-Aug-2019
|
||||
Python-Version: 3.9
|
||||
Python-Version: 3.10
|
||||
|
||||
|
||||
Abstract
|
||||
========
|
||||
|
||||
This PEP proposes a complementary syntax for ``Union[X,Y]`` and extends its
|
||||
purpose to ``isinstance`` and ``issubclass``.
|
||||
This PEP proposes overloading the ``|`` operator on types to allow
|
||||
writing ``Union[X, Y]`` as ``X | Y``, and allows it to appear in
|
||||
``isinstance`` and ``issubclass`` calls.
|
||||
|
||||
|
||||
Motivation
|
||||
==========
|
||||
|
||||
PEP 484 and PEP 526 propose a generic syntax to add typing to variables,
|
||||
parameters and function returns. PEP 585 proposes to
|
||||
`expose parameters to generics at runtime <https://www.python.org/dev/peps/pep-0585/#id7>`_.
|
||||
MyPy [1]_ accepts a syntax which looks like::
|
||||
parameters and function returns. PEP 585 proposes to `expose
|
||||
parameters to generics at runtime
|
||||
<https://www.python.org/dev/peps/pep-0585/#parameters-to-generics-are-available-at-runtime>`_.
|
||||
Mypy [1]_ accepts a syntax which looks like::
|
||||
|
||||
annotation: name_type
|
||||
name_type: NAME (args)?
|
||||
args: '[' paramslist ']'
|
||||
paramslist: annotation (',' annotation)* [',']
|
||||
|
||||
- To describe a disjunction, the user must use ``Union[X,Y]``.
|
||||
- To describe a disjunction (union type), the user must use ``Union[X, Y]``.
|
||||
|
||||
The verbosity of this syntax does not help the adoption.
|
||||
|
||||
|
||||
Proposal
|
||||
========
|
||||
|
||||
Inspired by Scala language [2]_ and Pike [3]_, this proposal adds operator ``type.__or__()``.
|
||||
With this new operator, it is possible to write ``int | str`` instead of
|
||||
``Union[int,str]``. The result of this expression would then be valid in
|
||||
Inspired by Scala [2]_ and Pike [3]_, this proposal adds operator
|
||||
``type.__or__()``. With this new operator, it is possible to write
|
||||
``int | str`` instead of ``Union[int, str]``. In addition to
|
||||
annotations, the result of this expression would then be valid in
|
||||
``isinstance()`` and ``issubclass()``::
|
||||
|
||||
isinstance(5, int | str)
|
||||
issubclass(bool, int | float)
|
||||
|
||||
We will also be able to write ``t | None`` or ``None | t`` instead of
|
||||
``Optional[t]``::
|
||||
|
||||
isinstance(None, int | None)
|
||||
isinstance(42, None | int)
|
||||
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
|
@ -52,7 +63,7 @@ Here are some examples of what we can do with this feature.
|
|||
|
||||
::
|
||||
|
||||
# in place of
|
||||
# Instead of
|
||||
# def f(list: List[Union[int, str]], param: Optional[int]) -> Union[float, str]
|
||||
def f(list: List[int | str], param: int | None) -> float | str:
|
||||
pass
|
||||
|
@ -65,35 +76,40 @@ Here are some examples of what we can do with this feature.
|
|||
assert isinstance("", int | str)
|
||||
assert issubclass(bool, int | float)
|
||||
|
||||
Once the Python language is extended, MyPy [1]_ and other type checkers will
|
||||
Once the Python language is extended, mypy [1]_ and other type checkers will
|
||||
need to be updated to accept this new syntax.
|
||||
|
||||
Technical point of view
|
||||
=======================
|
||||
To accept to extend ``isinstance()`` and ``issubclass()``, the object ``_GenericAlias`` must be available as a core,
|
||||
that doesn't have a directly-accessible name but via alias in typing module..
|
||||
|
||||
Implementation
|
||||
==============
|
||||
|
||||
A new built-in ``Union`` type must be implemented to hold the return
|
||||
value of ``t1 | t2``, and it must be supported by ``isinstance()`` and
|
||||
``issubclass()``. This type can be placed in the ``types`` module.
|
||||
Interoperability between ``types.Union`` and ``typing.Union`` must be
|
||||
provided.
|
||||
|
||||
|
||||
Incompatible changes
|
||||
====================
|
||||
|
||||
In some situations, some exceptions will not be raised as expected.
|
||||
|
||||
For backward compatibility, ``typing.py`` must say ``_GenericAlias = _GenericAlias``.
|
||||
|
||||
If a metaclass implements the ``__or__`` operator, it will override this::
|
||||
|
||||
>>> class M(type):
|
||||
... def __or__(self,other): return "Hello"
|
||||
... def __or__(self, other): return "Hello"
|
||||
...
|
||||
>>> class C(metaclass=M):pass
|
||||
>>> class C(metaclass=M): pass
|
||||
...
|
||||
>>> C | int
|
||||
'Hello'
|
||||
>>> int | C
|
||||
typing.Union[int, __main__.C]
|
||||
>>> Union[C,int]
|
||||
>>> Union[C, int]
|
||||
typing.Union[__main__.C, int]
|
||||
|
||||
|
||||
Objections and responses
|
||||
========================
|
||||
|
||||
|
@ -120,8 +136,8 @@ CONS:
|
|||
Pytype, and who knows what else (it's a minor change see "Reference Implementation"
|
||||
|
||||
|
||||
Change only the PEP 484 (Type hints) to accept the syntax ``type1 | type2`` ?
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Change only PEP 484 (Type hints) to accept the syntax ``type1 | 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()``).
|
||||
|
@ -157,16 +173,16 @@ CONS:
|
|||
Reference Implementation
|
||||
========================
|
||||
|
||||
A proposed implementation for `cpython is here
|
||||
<https://github.com/pprados/cpython/tree/PEP604>`_.
|
||||
A proposed implementation for `mypy is here
|
||||
<https://github.com/pprados/mypy/tree/PEP604>`_.
|
||||
- A proposed implementation for `cpython is here
|
||||
<https://github.com/python/cpython/pull/21515>`_.
|
||||
- A proposed implementation for `mypy is here
|
||||
<https://github.com/pprados/mypy/tree/PEP604>`_.
|
||||
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] MyPy
|
||||
.. [1] mypy
|
||||
http://mypy-lang.org/
|
||||
.. [2] Scala Union Types
|
||||
https://dotty.epfl.ch/docs/reference/new-types/union-types.html
|
||||
|
|
Loading…
Reference in New Issue