[pep-585] Type Hinting Usability Conventions (WIP)
This commit is contained in:
parent
595563b534
commit
c7881a5216
|
@ -0,0 +1,147 @@
|
|||
PEP: 585
|
||||
Title: Type Hinting Usability Conventions
|
||||
Version: $Revision$
|
||||
Last-Modified: $Date$
|
||||
Author: Łukasz Langa <lukasz@python.org>
|
||||
Discussions-To: Python-Dev <python-dev@python.org>
|
||||
Status: Draft
|
||||
Type: Standards Track
|
||||
Content-Type: text/x-rst
|
||||
Created: 03-Mar-2019
|
||||
Python-Version: 3.8
|
||||
|
||||
Status of this PEP
|
||||
==================
|
||||
|
||||
The draft of this PEP is not yet complete. I am shamelessly squatting
|
||||
on the PEP number which provides a cute relation to the original PEP 484.
|
||||
The draft will be completed in the upcoming days.
|
||||
|
||||
Abstract
|
||||
========
|
||||
|
||||
Static typing as defined by PEPs 484, 526, 544, 560, and 563 was built
|
||||
incrementally on top of the existing Python runtime and constrained by
|
||||
existing syntax and runtime behavior. For this reason, its usability is
|
||||
lacking and some parts of typing necessarily feel like an afterthought.
|
||||
|
||||
This PEP addresses some of the major complaints of typing users, namely:
|
||||
|
||||
* the necessity for programmers to perform import book-keeping of names
|
||||
only used in static typing contexts;
|
||||
* the surprising placement of runtime collections in the typing module
|
||||
(ABCs and ``NamedTuple``);
|
||||
* the surprising dichotomy between ``List`` and ``list``, and so on;
|
||||
* parts of static typing still performed at runtime (aliasing, cast,
|
||||
``NewType``, ``TypeVar``).
|
||||
|
||||
Rationale and Goals
|
||||
===================
|
||||
|
||||
The overarching goal of this PEP is to make static typing fully free of
|
||||
runtime side effects. In other words, no operations related to the
|
||||
process of annotating arguments, return values, and variables with types
|
||||
should generate runtime behavior which is otherwise useless at runtime.
|
||||
|
||||
Backwards compatibility
|
||||
=======================
|
||||
|
||||
This PEP is fully backwards compatible. Code written in previous ways
|
||||
might trigger some deprecations but will ultimately work as intended.
|
||||
|
||||
The newly described functionality requires Python 3.7 (for uses of
|
||||
the "annotations" future-import) or Python 3.8 (for refactorings of the
|
||||
``typing`` module).
|
||||
|
||||
Tooling, including type checkers and linters, will have to be adapted to
|
||||
enable the new functionality.
|
||||
|
||||
Implementation
|
||||
==============
|
||||
|
||||
Syntactic support for generics on builtin types within annotations
|
||||
------------------------------------------------------------------
|
||||
|
||||
Starting with Python 3.7, when ``from __future__ import annotations`` is
|
||||
used, function and variable annotations can specify generics directly on
|
||||
builtin types. Example::
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
def find(haystack: dict[str, list[int]]) -> int:
|
||||
...
|
||||
|
||||
This new way is preferred, the names ``List``, ``Dict``, ``FrozenSet``,
|
||||
``Set`` are deprecated. They won't be removed from the ``typing`` module
|
||||
for backwards compatibility but type checkers may warn about them in
|
||||
future versions when used in conjunction with the "annotations" future
|
||||
import.
|
||||
|
||||
Note: no runtime component is added to builtin collections to facilitate
|
||||
generics in any sense. This syntax is only supported in an annotation.
|
||||
|
||||
Importing of typing
|
||||
-------------------
|
||||
|
||||
Starting with Python 3.7, when ``from __future__ import annotations`` is
|
||||
used, function and variable annotations can use special names from the
|
||||
``typing`` module without the relevant explicit imports being present
|
||||
in the module.
|
||||
|
||||
Example::
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
def loads(
|
||||
input: Union[str, bytes], *, encoding: Optional[str] = None
|
||||
) -> dict[str, Any]:
|
||||
...
|
||||
|
||||
Runtime collections in typing
|
||||
-----------------------------
|
||||
|
||||
All abstract base classes redefined in the typing module are being moved
|
||||
back to ``collections.abc`` including all additional functionality they
|
||||
gained in the typing module (in particular, generics support). The
|
||||
``Generic`` type is also moved to ``collections.abc``.
|
||||
|
||||
``typing.NamedTuple`` is also moved to ``collections``.
|
||||
|
||||
Aliases for all moved names will remain in the `typing` module for
|
||||
backwards compatibility. Using them directly becomes deprecated.
|
||||
|
||||
Moving the remaining runtime syntax for typing-related functionality to annotations
|
||||
-----------------------------------------------------------------------------------
|
||||
|
||||
Aliasing, cast, ``NewType``, and ``TypeVar`` require definitions which
|
||||
have a runtime effect. This means they require importing names from
|
||||
typing, cannot support forward references, and have negative (even if
|
||||
minimal) effect on runtime performance.
|
||||
|
||||
New syntax for those looks like this::
|
||||
|
||||
FBID: NewType[int]
|
||||
some_fbid: Cast[FBID] = some_int_from_db
|
||||
Inbox: Alias[dict[FBID, list[Message]]]
|
||||
T: TypeVar
|
||||
XXX: How to bind in TypeVar?
|
||||
|
||||
All of the above use the variable annotation syntax, removing the
|
||||
runtime component from the functionality. In the case of NewType and
|
||||
TypeVar, they additionally remove the necessity to repeat yourself with
|
||||
the name of the type variable.
|
||||
|
||||
Rejected alternatives
|
||||
=====================
|
||||
|
||||
Do nothing
|
||||
----------
|
||||
|
||||
The usability issues described in the abstract are increasingly visible
|
||||
when a codebase adopts type hinting holistically. The need to jump
|
||||
between the type the programmer is just describing and imports needed to
|
||||
describe the type breaks the flow of thought. The need to import
|
||||
lookalike built-in collections for generics within annotations is a
|
||||
kludge which makes it harder to teach Python and looks inelegant. The
|
||||
remaining runtime component, even with use of the "annotations"
|
||||
future-import, impacts startup performance of annotated applications.
|
Loading…
Reference in New Issue