155 lines
5.3 KiB
ReStructuredText
155 lines
5.3 KiB
ReStructuredText
PEP: 645
|
||
Title: Allow writing optional types as ``x?``
|
||
Author: Maggie Moss <maggiebmoss@gmail.com>
|
||
Sponsor: Guido van Rossum <guido@python.org>
|
||
Status: Draft
|
||
Type: Process
|
||
Content-Type: text/x-rst
|
||
Created: 25-Aug-2020
|
||
|
||
|
||
Abstract
|
||
========
|
||
This PEP proposes adding a ``?`` operator for types to allow writing ``int?`` in place of ``Optional[int]``.
|
||
|
||
|
||
Motivation
|
||
==========
|
||
Types have become a valuable and powerful part of the Python language. However, many type annotations are verbose and add
|
||
considerable friction to using type annotations. By improving the typing syntax, adding types to Python code becomes simpler
|
||
and improves the development experience for Python users.
|
||
|
||
In a similar vein, a PEP to introduce short hand syntax for :pep:`Union types <604>` has
|
||
been approved and implemented.
|
||
|
||
|
||
Rationale
|
||
=========
|
||
|
||
Types in Python can be quite verbose, this can be a hindrance when working towards type adoption. Making types more ergonomic,
|
||
as was done with the Union type in :pep:`604` (e.g., int | str), would reduce the effort needed to add types to new and existing Python code.
|
||
The Optional annotation is used frequently in both partially and fully typed Python code bases. In a small sampling of `5 well-typed open
|
||
source projects, on average 7% of annotations
|
||
<https://gist.github.com/MaggieMoss/fd8dfe002b2702fae243dbf81a62624e>`_ [2] included at least one optional type. This indicates
|
||
that updating the syntax has the potential to make types more concise, reduce code length and improve readability.
|
||
|
||
Simplifying the syntax for optionals has been `discussed previously <https://github.com/python/typing/issues/429>`_ [3] within the typing community.
|
||
The consensus during these conversations has been that ``?`` is the preferred operator. There is no native support for unary ``?`` in Python and this will
|
||
need to be added to the runtime.
|
||
|
||
Adding the ? sigil to the Python grammar has been proposed previously in :pep:`505`, which is currently in a deferred state.
|
||
:pep:`505` proposes a:
|
||
|
||
- "None coalescing" binary operator ``??``
|
||
|
||
- "None-aware attribute access" operator ``?.`` ("maybe dot")
|
||
|
||
- "None-aware indexing" operator ``?[]`` ("maybe subscript")
|
||
|
||
|
||
Should :pep:`505` be approved in the future, it would not interfere with the typing specific ``?`` proposed in this PEP. As well,
|
||
since all uses of the ``?`` would be conceptually related, it would not be confusing in terms of learning Python or a hindrance to quick visual comprehension.
|
||
|
||
The proposed syntax, with the postfix operator, mimics the optional syntax found in other typed languages, like C#, TypeScript and Swift.
|
||
The widespread adoption and popularity of these languages means that Python developers are likely already familiar with this syntax.::
|
||
|
||
// Optional in Swift
|
||
var example: String?
|
||
|
||
// Optional in C#
|
||
string? example;
|
||
|
||
Adding this syntax would also follow the often used pattern of using builtin types as annotations. For example, ``list``, ``dict`` and ``None``. This would allow more annotations to be
|
||
added to Python code without importing from ``typing``.
|
||
|
||
|
||
Specification
|
||
=============
|
||
|
||
The new optional syntax should be accepted for function, variable, attribute and parameter annotations.
|
||
|
||
::
|
||
|
||
# instead of
|
||
# def foo(x: Optional[int], y: Optional[str], z: Optional[list[int]): ...
|
||
def foo(x: int?, y: str?, x: list[int]?): ...
|
||
|
||
# def bar(x: list[typing.Optional[int]]): ...
|
||
def bar(x: list[int?]): ...
|
||
|
||
The new optional syntax should be equivalent to the existing typing.Optional syntax
|
||
|
||
::
|
||
|
||
typing.Optional[int] == int?
|
||
|
||
The new optional syntax should have the same identity as the existing typing.Optional syntax.
|
||
|
||
::
|
||
|
||
typing.Optional[int] is int?
|
||
|
||
|
||
It should also be equivalent to a Union with None.
|
||
|
||
::
|
||
|
||
# old syntax
|
||
int? == typing.Union[int, None]
|
||
|
||
# new syntax
|
||
int? == int | None
|
||
|
||
Since the new Union syntax specified in :pep:`604` is supported in ``isinstance`` and ``issubclass``, the new optional syntax should be supported in both ``isinstance`` and ``issubclass``,
|
||
|
||
::
|
||
|
||
isinstance(1, int?) # true
|
||
issubclass(Child, Super?) # true
|
||
|
||
A new dunder method will need to be implemented to allow the ``?`` operator to be overloaded for other functionality.
|
||
|
||
|
||
Backwards Compatibility
|
||
=======================
|
||
|
||
``?`` is currently unused in Python syntax, therefore this PEP is fully backwards compatible.
|
||
|
||
Reference Implementation
|
||
========================
|
||
|
||
A reference implementation can be found `here <https://github.com/python/cpython/compare/master...MaggieMoss:new-optional-syntax-postfix>`_ [5].
|
||
|
||
Rejected Ideas
|
||
==============
|
||
|
||
Discussed alternatives were
|
||
|
||
* The ``~`` operator was considered in place of ``?``.
|
||
* A prefix operator (``?int``).
|
||
|
||
|
||
References
|
||
==========
|
||
|
||
.. [2] Use of Optional Annotations in Open Source Python projects
|
||
(https://gist.github.com/MaggieMoss/fd8dfe002b2702fae243dbf81a62624e)
|
||
.. [3] Github Issue Discussion of Optional syntax
|
||
(https://github.com/python/typing/issues/429)
|
||
.. [5] Reference Implementation
|
||
(https://github.com/python/cpython/compare/master...MaggieMoss:new-optional-syntax-postfix)
|
||
|
||
Copyright
|
||
=========
|
||
|
||
This document is placed in the public domain or under the CC0-1.0-Universal license, whichever is more permissive.
|
||
|
||
..
|
||
Local Variables:
|
||
mode: indented-text
|
||
indent-tabs-mode: nil
|
||
sentence-end-double-space: t
|
||
fill-column: 70
|
||
coding: utf-8
|
||
End:
|