Update rules for function annotations in the light of PEP 484.

This commit is contained in:
Guido van Rossum 2016-01-05 10:33:30 -08:00
parent 8288ff6a15
commit 146574f68a
1 changed files with 77 additions and 53 deletions

View File

@ -520,22 +520,33 @@ Other Recommendations
def complex(real, imag = 0.0):
return magic(r = real, i = imag)
- Do use spaces around the ``=`` sign of an annotated function definition.
Additionally, use a single space after the ``:``, as well as a single space
on either side of the ``->`` sign representing an annotated return value.
- Function annotations should use the normal rules for colons and
always have spaces around the ``->`` arrow if present. (See
`Function Annotations`_ below for more about function annotations.)
Yes::
def munge(input: AnyStr):
def munge(sep: AnyStr = None):
def munge() -> AnyStr:
def munge(input: AnyStr, sep: AnyStr = None, limit=1000):
def munge(input: AnyStr): ...
def munge() -> AnyStr: ...
No::
def munge(input: AnyStr=None):
def munge(input:AnyStr):
def munge(input: AnyStr)->PosInt:
def munge(input:AnyStr): ...
def munge()->PosInt: ...
- When combining an argument annotation with a default value, use
spaces around the ``=`` sign (but only for those arguments that have
both an annotation and a default).
Yes::
def munge(sep: AnyStr = None): ...
def munge(input: AnyStr, sep: AnyStr = None, limit=1000): ...
No::
def munge(input: AnyStr=None): ...
def munge(input: AnyStr, limit = 1000): ...
- Compound statements (multiple statements on the same line) are
generally discouraged.
@ -1233,60 +1244,65 @@ Programming Recommendations
No: if greeting == True:
Worse: if greeting is True:
- The Python standard library will not use function annotations as
that would result in a premature commitment to a particular
annotation style. Instead, the annotations are left for users to
discover and experiment with useful annotation styles.
Function Annotations
--------------------
It is recommended that third party experiments with annotations use an
associated decorator to indicate how the annotation should be
interpreted.
With the acceptance of PEP 484, the style rules for function
annotations are changing.
Early core developer attempts to use function annotations revealed
inconsistent, ad-hoc annotation styles. For example:
- In order to be forward compatible, function annotations in Python 3
code should preferably use PEP 484 syntax. (There are some
formatting recommendations for annotations in the previous section.)
* ``[str]`` was ambiguous as to whether it represented a list of
strings or a value that could be either *str* or *None*.
- The experimentation with annotation styles that was recommended
previously in this PEP is no longer encouraged.
* The notation ``open(file:(str,bytes))`` was used for a value that
could be either *bytes* or *str* rather than a 2-tuple containing
a *str* value followed by a *bytes* value.
- However, experiments within the rules of PEP 484 are now encouraged.
For example, marking up a large library with PEP 484 style type
annotations, reviewing how easy it was to add those annotations, and
observing whether their presence increases code understandabilty.
* The annotation ``seek(whence:int)`` exhibited a mix of
over-specification and under-specification: *int* is too
restrictive (anything with ``__index__`` would be allowed) and it
is not restrictive enough (only the values 0, 1, and 2 are
allowed). Likewise, the annotation ``write(b: bytes)`` was also
too restrictive (anything supporting the buffer protocol would be
allowed).
- The Python standard library should be conservative in adopting such
annotations, but their use is allowed for new code and for big
refactorings.
* Annotations such as ``read1(n: int=None)`` were self-contradictory
since *None* is not an *int*. Annotations such as
``source_path(self, fullname:str) -> object`` were confusing about
what the return type should be.
- For code that wants to make a different use of function annotations
it is recommended to put a comment of the form::
* In addition to the above, annotations were inconsistent in the use
of concrete types versus abstract types: *int* versus *Integral*
and set/frozenset versus MutableSet/Set.
# type: ignore
* Some annotations in the abstract base classes were incorrect
specifications. For example, set-to-set operations require
*other* to be another instance of *Set* rather than just an
*Iterable*.
near the top of the file; this tells type checker to ignore all
annotations. (More fine-grained ways of disabling complaints from
type checkers can be found in PEP 484.)
* A further issue was that annotations become part of the
specification but weren't being tested.
- Like linters, type checkers are optional, separate tools. Python
interpreters by default should not issue any messages due to type
checking and should not alter their behavior based on annotations.
* In most cases, the docstrings already included the type
specifications and did so with greater clarity than the function
annotations. In the remaining cases, the docstrings were improved
once the annotations were removed.
- Users who don't want to use type checkers are free to ignore them.
However, it is expected that users of library packages may want to
run type checkers over those library packages. For this purpose PEP
484 recommends the use of stub files: .pyi files that are read by
the type checker in preference of the corresponding .py files. Stub
files can be distributed with a library, or separately (with the
library author's permission) through the _typeshed_ repo [5]_.
* The observed function annotations were too ad-hoc and inconsistent
to work with a coherent system of automatic type checking or
argument validation. Leaving these annotations in the code would
have made it more difficult to make changes later so that
automated utilities could be supported.
- For code that needs to be backwards compatible, function annotations
can be added in the form of comments. Basically, this Python 3 annotation::
def embezzle(self, account: str, funds: int = 1000000, **fake_receipts: str) -> None:
"""Embezzle funds from account using fake receipts."""
<code goes here>
is equivalent to the following::
def embezzle(self, account, funds=1000000, **fake_receipts):
# type: (str, int, **str) -> None
"""Embezzle funds from account using fake receipts."""
<code goes here>
The _mypy_ type checker [6]_ currently support this syntax, and other
type checkers are encouraged to adopt it.
.. rubric:: Footnotes
@ -1312,6 +1328,14 @@ References
.. [4] PEP 8 modernisation, July 2013
http://bugs.python.org/issue18472
.. [5] Typeshed repo
https://github.com/python/typeshed
.. [6] mypy type checker
http://mypy-lang.org
https://github.com/JukkaL/mypy
Copyright
=========