PEP 589: Small updates based on feedback from @gvanrossum (#1060)

These are the updates I promised in https://github.com/python/peps/pull/991.
This commit is contained in:
Jukka Lehtosalo 2019-05-20 18:50:00 +01:00 committed by Guido van Rossum
parent 9d2abd5db3
commit 92c6ff0d9b
1 changed files with 57 additions and 11 deletions

View File

@ -372,9 +372,9 @@ Discussion:
f(b) # Type check error: 'B' not compatible with 'A'
b['x'] + 1 # Runtime error: None + 1
* A TypedDict type with required keys is not consistent with a
TypedDict type with non-required keys, since the latter allows keys
to be deleted. Example where this is relevant::
* A TypedDict type with a required key is not consistent with a
TypedDict type where the same key is a non-required key, since the
latter allows keys to be deleted. Example where this is relevant::
class A(TypedDict, total=False):
x: int
@ -479,8 +479,9 @@ the most important type safety violations to prevent:
3. A key that is not defined in the TypedDict type is added.
A key that is not a literal should generally be rejected, since its
value is unknown during type checking, and thus can cause some of
the above violations.
value is unknown during type checking, and thus can cause some of the
above violations. (`Use of Final Values and Literal Types`_
generalizes this to cover final names and literal types.)
The use of a key that is not known to exist should be reported as an
error, even if this wouldn't necessarily generate a runtime type
@ -503,9 +504,15 @@ Type checkers should reject the following operations on TypedDict
objects as unsafe, even though they are valid for normal dictionaries:
* Operations with arbitrary ``str`` keys (instead of string literals
or other expressions with known string values) should be rejected.
This involves both destructive operations such as setting an item
and read-only operations such as subscription expressions.
or other expressions with known string values) should generally be
rejected. This involves both destructive operations such as setting
an item and read-only operations such as subscription expressions.
As an exception to the above rule, ``d.get(e)`` and ``e in d``
should be allowed for TypedDict objects, for an arbitrary expression
``e`` with type ``str``. The motivation is that these are safe and
can be useful for introspecting TypedDict objects. The static type
of ``d.get(e)`` should be ``object`` if the string value of ``e``
cannot be determined statically.
* ``clear()`` is not safe since it could remove required keys, some of
which may not be directly visible because of structural
@ -527,6 +534,33 @@ In some cases potentially unsafe operations may be accepted if the
alternative is to generate false positive errors for idiomatic code.
Use of Final Values and Literal Types
-------------------------------------
Type checkers should allow final names (PEP 591 [#PEP-591]_) with
string values to be used instead of string literals in operations on
TypedDict objects. For example, this is valid::
YEAR: Final = 'year'
m: Movie = {'name': 'Alien', 'year': 1979}
years_since_epoch = m[YEAR] - 1970
Similarly, an expression with a suitable literal type
(PEP 586 [#PEP-586]_) can be used instead of a literal value::
def get_value(movie: Movie,
key: Literal['year', 'name']) -> Union[int, str]:
return movie[key]
Type checkers are only expected to support actual string literals, not
final names or literal types, for specifying keys in a TypedDict type
definition. Also, only a boolean literal can be used to specify
totality in a TypedDict definition. The motivation for this is to
make type declarations self-contained, and to simplify the
implementation of type checkers.
Backwards Compatibility
=======================
@ -544,7 +578,9 @@ Reference Implementation
The mypy [#mypy]_ type checker supports TypedDict types. A reference
implementation of the runtime component is provided in the
``mypy_extensions`` [#mypy_extensions]_ module.
``typing_extensions`` [#typing_extensions]_ module. The original
implementation was in the ``mypy_extensions`` [#mypy_extensions]_
module.
Rejected Alternatives
@ -576,7 +612,7 @@ this proposal:
* TypedDict types can't be used in ``isinstance()`` or ``issubclass()``
checks. The reasoning is similar to why runtime type checks aren't
supported in general.
supported in general with many type hints.
These features were left out from this PEP, but they are potential
extensions to be added in the future:
@ -588,7 +624,8 @@ extensions to be added in the future:
dictionary type.
* There is no way to individually specify whether each key is required
or not. No proposed syntax was clear enough.
or not. No proposed syntax was clear enough, and we expect that
there is limited need for this.
* TypedDict can't be used for specifying the type of a ``**kwargs``
argument. This would allow restricting the allowed keyword
@ -624,8 +661,17 @@ References
.. [#PEP-483] PEP 483, The Theory of Type Hints, van Rossum, Levkivskyi
(http://www.python.org/dev/peps/pep-0483)
.. [#PEP-591] PEP 591, Adding a final qualifier to typing, Sullivan,
Levkivskyi (http://www.python.org/dev/peps/pep-0591)
.. [#PEP-586] PEP 586, Literal Types, Lee, Levkivskyi, Lehtosalo
(http://www.python.org/dev/peps/pep-0586)
.. [#mypy] http://www.mypy-lang.org/
.. [#typing_extensions]
https://github.com/python/typing/tree/master/typing_extensions
.. [#mypy_extensions] https://github.com/python/mypy_extensions
.. [#typing_inspect] https://github.com/ilevkivskyi/typing_inspect