added PEP 3107, Function Annotations, by Winter & Lownds
This commit is contained in:
parent
9eb151a284
commit
6006113241
|
@ -105,6 +105,7 @@ Index by Category
|
||||||
S 3104 Access to Names in Outer Scopes Yee
|
S 3104 Access to Names in Outer Scopes Yee
|
||||||
S 3105 Make print a function Brandl
|
S 3105 Make print a function Brandl
|
||||||
S 3106 Revamping dict.keys(), .values() and .items() GvR
|
S 3106 Revamping dict.keys(), .values() and .items() GvR
|
||||||
|
S 3107 Function Annotations Winter, Lownds
|
||||||
|
|
||||||
Finished PEPs (done, implemented in Subversion)
|
Finished PEPs (done, implemented in Subversion)
|
||||||
|
|
||||||
|
@ -442,7 +443,8 @@ Numerical Index
|
||||||
S 3103 A Switch/Case Statement GvR
|
S 3103 A Switch/Case Statement GvR
|
||||||
S 3104 Access to Names in Outer Scopes Yee
|
S 3104 Access to Names in Outer Scopes Yee
|
||||||
S 3105 Make print a function Brandl
|
S 3105 Make print a function Brandl
|
||||||
S 3106 Revamping dict.keys(), .values() and .items() GvR
|
S 3106 Revamping dict.keys(), .values() and .items() GvR
|
||||||
|
S 3107 Function Annotations Winter, Lownds
|
||||||
|
|
||||||
Key
|
Key
|
||||||
|
|
||||||
|
@ -513,6 +515,7 @@ Owners
|
||||||
Lielens, Gregory gregory.lielens@fft.be
|
Lielens, Gregory gregory.lielens@fft.be
|
||||||
Lindqvist, Björn bjourne@gmail.com
|
Lindqvist, Björn bjourne@gmail.com
|
||||||
von Loewis, Martin loewis@informatik.hu-berlin.de
|
von Loewis, Martin loewis@informatik.hu-berlin.de
|
||||||
|
Lownds, Tony tony@pagedna.com
|
||||||
Martelli, Alex aleax@aleax.it
|
Martelli, Alex aleax@aleax.it
|
||||||
McClelland, Andrew eternalsquire@comcast.net
|
McClelland, Andrew eternalsquire@comcast.net
|
||||||
McMillan, Gordon gmcm@hypernet.com
|
McMillan, Gordon gmcm@hypernet.com
|
||||||
|
@ -549,6 +552,7 @@ Owners
|
||||||
Way, Terence terry@wayforward.net
|
Way, Terence terry@wayforward.net
|
||||||
Wells, Cliff LogiplexSoftware@earthlink.net
|
Wells, Cliff LogiplexSoftware@earthlink.net
|
||||||
Wilson, Greg gvwilson@ddj.com
|
Wilson, Greg gvwilson@ddj.com
|
||||||
|
Winter, Collin collinw@gmail.com
|
||||||
Wouters, Thomas thomas@xs4all.net
|
Wouters, Thomas thomas@xs4all.net
|
||||||
Yee, Ka-Ping ping@zesty.ca
|
Yee, Ka-Ping ping@zesty.ca
|
||||||
Zadka, Moshe moshez@zadka.site.co.il
|
Zadka, Moshe moshez@zadka.site.co.il
|
||||||
|
|
|
@ -0,0 +1,294 @@
|
||||||
|
PEP: 3107
|
||||||
|
Title: Function Annotations
|
||||||
|
Version: $Revision$
|
||||||
|
Last-Modified: $Date$
|
||||||
|
Author: Collin Winter <collinw@gmail.com>,
|
||||||
|
Tony Lownds <tony@pagedna.com>
|
||||||
|
Status: Draft
|
||||||
|
Type: Standards Track
|
||||||
|
Requires: 362
|
||||||
|
Content-Type: text/x-rst
|
||||||
|
Created: 2-Dec-2006
|
||||||
|
Python-Version: 3.0
|
||||||
|
Post-History:
|
||||||
|
|
||||||
|
|
||||||
|
Abstract
|
||||||
|
========
|
||||||
|
|
||||||
|
This PEP introduces a syntax for adding arbitrary metadata annotations
|
||||||
|
to Python functions [#functerm]_.
|
||||||
|
|
||||||
|
|
||||||
|
Rationale
|
||||||
|
=========
|
||||||
|
|
||||||
|
Because Python's 2.x series lacks a standard way of annotating a
|
||||||
|
function's parameters and return values (e.g., with information about
|
||||||
|
a what type a function's return value should be), a variety of tools
|
||||||
|
and libraries have appeared to fill this gap [#tailexamp]_. Some
|
||||||
|
utilise the decorators introduced in "PEP 318", while others parse a
|
||||||
|
function's docstring, looking for annotations there.
|
||||||
|
|
||||||
|
This PEP aims to provide a single, standard way of specifying this
|
||||||
|
information, reducing the confusion caused by the wide variation in
|
||||||
|
mechanism and syntax that has existed until this point.
|
||||||
|
|
||||||
|
|
||||||
|
Fundamentals of Function Annotations
|
||||||
|
====================================
|
||||||
|
|
||||||
|
Before launching into a discussion of the precise ins and outs of
|
||||||
|
Python 3.0's function annotations, let's first talk broadly about
|
||||||
|
what annotations are and are not:
|
||||||
|
|
||||||
|
1. Function annotations, both for parameters and return values, are
|
||||||
|
completely optional.
|
||||||
|
|
||||||
|
2. Function annotations are nothing more than a way of associating
|
||||||
|
arbitrary Python expressions with various parts of a function at
|
||||||
|
compile-time.
|
||||||
|
|
||||||
|
By itself, Python does not attach any particular meaning or
|
||||||
|
significance to annotations. Left to its own, Python simply makes
|
||||||
|
these expressions available as the values in the
|
||||||
|
``__signature__.annotations`` mapping described in `Accessing
|
||||||
|
Function Annotations`_ below.
|
||||||
|
|
||||||
|
The only way that annotations take on meaning is when they are
|
||||||
|
interpreted by third-party libraries. These annotation consumers
|
||||||
|
can do anything they want with a function's annotations. For
|
||||||
|
example, one library might use string-based annotations to provide
|
||||||
|
improved help messages, like so::
|
||||||
|
|
||||||
|
def compile(source: "something compilable",
|
||||||
|
filename: "where the compilable thing comes from",
|
||||||
|
mode: "is this a single statement or a suite?"):
|
||||||
|
...
|
||||||
|
|
||||||
|
Another library might be used to provide typechecking for Python
|
||||||
|
functions and methods. This library could use annotations to
|
||||||
|
indicate the function's expected input and return types, possibly
|
||||||
|
something like ::
|
||||||
|
|
||||||
|
def haul(item: Haulable, *vargs: PackAnimal) -> Distance:
|
||||||
|
...
|
||||||
|
|
||||||
|
However, neither the strings in the first example nor the
|
||||||
|
type information in the second example have any meaning on their
|
||||||
|
own; meaning comes from third-party libraries alone.
|
||||||
|
|
||||||
|
3. Following from point 2, this PEP makes no attempt to introduce
|
||||||
|
any kind of standard semantics, even for the built-in types.
|
||||||
|
This work will be left to third-party libraries.
|
||||||
|
|
||||||
|
There is no worry that these libraries will assign semantics at
|
||||||
|
random, or that a variety of libraries will appear, each with
|
||||||
|
varying semantics and interpretations of what, say, a tuple of
|
||||||
|
strings means. The difficulty inherent in writing annotation
|
||||||
|
interpreting libraries will keep their number low and their
|
||||||
|
authorship in the hands of people who, frankly, know what they're
|
||||||
|
doing.
|
||||||
|
|
||||||
|
|
||||||
|
Syntax
|
||||||
|
======
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
|
||||||
|
Annotations for parameters take the form of optional expressions that
|
||||||
|
follow the parameter name. This example indicates that parameters 'a'
|
||||||
|
and 'c' should both be a ``Number``, while parameter 'b' should both
|
||||||
|
be a ``Mapping``::
|
||||||
|
|
||||||
|
def foo(a: Number, b: Mapping, c: Number = 5):
|
||||||
|
...
|
||||||
|
|
||||||
|
(Number, Mapping and Sequence are used thoughout this PEP and
|
||||||
|
represent the standard `numeric`_, `mapping`_ and `sequence
|
||||||
|
protocols`_.)
|
||||||
|
|
||||||
|
In pseudo-grammar, parameters now look like ``identifier [:
|
||||||
|
expression] [= expression]``. That is, type annotations always
|
||||||
|
precede a parameter's default value and both type annotations and
|
||||||
|
default values are optional. Just like how equal signs are used to
|
||||||
|
indicate a default value, colons are used to mark annotations. All
|
||||||
|
annotation expressions are evaluated when the function definition is
|
||||||
|
executed.
|
||||||
|
|
||||||
|
Annotations for excess parameters (i.e., ``*args`` and ``**kwargs``)
|
||||||
|
are indicated similarly. In the following function definition,
|
||||||
|
``*args`` is flagged as a list of ``Number``, and ``**kwargs`` is
|
||||||
|
marked as a dict whose keys are strings and whose values are of type
|
||||||
|
``Sequence``. ::
|
||||||
|
|
||||||
|
def foo(*args: Number, **kwargs: Sequence):
|
||||||
|
...
|
||||||
|
|
||||||
|
Note that, depending on what annotation-interpreting library you're
|
||||||
|
using, the following might also be a valid spelling of the above::
|
||||||
|
|
||||||
|
def foo(*args: [Number], **kwargs: {str: Sequence}):
|
||||||
|
...
|
||||||
|
|
||||||
|
Only the first, however, has the BDFL's blessing [#blessedexcess]_ as
|
||||||
|
the One Obvious Way.
|
||||||
|
|
||||||
|
|
||||||
|
Return Values
|
||||||
|
-------------
|
||||||
|
|
||||||
|
The examples thus far have omitted examples of how to annotate the
|
||||||
|
type of a function's return value. This is done like so::
|
||||||
|
|
||||||
|
def sum(*args: Number) -> Number:
|
||||||
|
...
|
||||||
|
|
||||||
|
The parameter list can now be followed by a literal ``->`` and a
|
||||||
|
Python expression. Like the annotations for parameters, this
|
||||||
|
expression will be evaluated when the function definition is executed.
|
||||||
|
|
||||||
|
The grammar for function definitions [#grammar]_ is now something like
|
||||||
|
::
|
||||||
|
|
||||||
|
funcdef ::= [decorators] "def" funcname "("
|
||||||
|
[parameter_list] ")" ["->" expression] ":" suite
|
||||||
|
decorators ::= decorator+
|
||||||
|
decorator ::= "@" dotted_name ["(" [argument_list
|
||||||
|
[","]] ")"] NEWLINE
|
||||||
|
dotted_name ::= identifier ("." identifier)*
|
||||||
|
parameter_list ::= (defparameter ",")*
|
||||||
|
( "*" identifier [":" expression]
|
||||||
|
[, "**" identifier [":" expression] ]
|
||||||
|
| "**" identifier [":" expression]
|
||||||
|
| defparameter [","] )
|
||||||
|
defparameter ::= parameter [":" expression] ["=" expression]
|
||||||
|
sublist ::= parameter ("," parameter)* [","]
|
||||||
|
parameter ::= identifier | "(" sublist ")"
|
||||||
|
funcname ::= identifier
|
||||||
|
|
||||||
|
|
||||||
|
Accessing Function Annotations
|
||||||
|
==============================
|
||||||
|
|
||||||
|
Once compiled, a function's annotations are available via the
|
||||||
|
function's ``__signature__`` attribute, introduced by PEP 362.
|
||||||
|
Signature objects include an attribute just for annotations,
|
||||||
|
appropriately called ``annotations``. This attribute is a dictionary,
|
||||||
|
mapping parameter names to an object representing the evaluated
|
||||||
|
annotation expression.
|
||||||
|
|
||||||
|
There is a special key in the ``annotations`` mapping, ``"return"``.
|
||||||
|
This key is present only if an annotation was supplied for the
|
||||||
|
function's return value.
|
||||||
|
|
||||||
|
For example, the following annotation::
|
||||||
|
|
||||||
|
def foo(a: Number, b: 5 + 6, c: list) -> String:
|
||||||
|
...
|
||||||
|
|
||||||
|
would result in a ``__signature__.annotations`` mapping of ::
|
||||||
|
|
||||||
|
{'a': Number,
|
||||||
|
'b': 11,
|
||||||
|
'c': list,
|
||||||
|
'return': String}
|
||||||
|
|
||||||
|
The ``return`` key was chosen because it cannot conflict with the name
|
||||||
|
of a parameter; any attempt to use ``return`` as a parameter name
|
||||||
|
would result in a ``SyntaxError``.
|
||||||
|
|
||||||
|
|
||||||
|
Implementation
|
||||||
|
==============
|
||||||
|
|
||||||
|
A sample implementation has been provided [#implementation]_ by Tony
|
||||||
|
Lownds.
|
||||||
|
|
||||||
|
|
||||||
|
Rejected Proposals
|
||||||
|
==================
|
||||||
|
|
||||||
|
+ The BDFL rejected the author's idea for a special syntax for adding
|
||||||
|
annotations to generators as being "too ugly" [#rejectgensyn]_.
|
||||||
|
|
||||||
|
+ Though discussed early on ([#threadgen]_, [#threadhof]_), including
|
||||||
|
special objects in the stdlib for annotating generator functions and
|
||||||
|
higher-order functions was ultimately rejected as being more
|
||||||
|
appropriate for third-party libraries; including them in the
|
||||||
|
standard library raised too many thorny issues.
|
||||||
|
|
||||||
|
+ Despite considerable discussion about a standard type
|
||||||
|
parameterisation syntax, it was decided that this should also be
|
||||||
|
left to third-party libraries. ([#threadimmlist]_, [#threadmixing]_,
|
||||||
|
[#emphasistpls]_)
|
||||||
|
|
||||||
|
|
||||||
|
References and Footnotes
|
||||||
|
========================
|
||||||
|
|
||||||
|
.. [#functerm] Unless specifically stated, "function" is generally
|
||||||
|
used as a synonym for "callable" throughout this document.
|
||||||
|
|
||||||
|
.. [#tailexamp] The author's typecheck_ library makes use of
|
||||||
|
decorators, while `Maxime Bourget's own typechecker`_ utilises
|
||||||
|
parsed docstrings.
|
||||||
|
|
||||||
|
.. [#blessedexcess]
|
||||||
|
http://mail.python.org/pipermail/python-3000/2006-May/002173.html
|
||||||
|
|
||||||
|
.. [#rejectgensyn]
|
||||||
|
http://mail.python.org/pipermail/python-3000/2006-May/002103.html
|
||||||
|
|
||||||
|
.. _typecheck:
|
||||||
|
http://oakwinter.com/code/typecheck/
|
||||||
|
|
||||||
|
.. _Maxime Bourget's own typechecker:
|
||||||
|
http://maxrepo.info/taxonomy/term/3,6/all
|
||||||
|
|
||||||
|
.. [#threadgen]
|
||||||
|
http://mail.python.org/pipermail/python-3000/2006-May/002091.html
|
||||||
|
|
||||||
|
.. [#threadhof]
|
||||||
|
http://mail.python.org/pipermail/python-3000/2006-May/001972.html
|
||||||
|
|
||||||
|
.. [#threadimmlist]
|
||||||
|
http://mail.python.org/pipermail/python-3000/2006-May/002105.html
|
||||||
|
|
||||||
|
.. [#threadmixing]
|
||||||
|
http://mail.python.org/pipermail/python-3000/2006-May/002209.html
|
||||||
|
|
||||||
|
.. [#emphasistpls]
|
||||||
|
http://mail.python.org/pipermail/python-3000/2006-June/002438.html
|
||||||
|
|
||||||
|
.. [#implementation]
|
||||||
|
http://python.org/sf/1607548
|
||||||
|
|
||||||
|
.. _numeric:
|
||||||
|
http://docs.python.org/lib/typesnumeric.html
|
||||||
|
|
||||||
|
.. _mapping:
|
||||||
|
http://docs.python.org/lib/typesmapping.html
|
||||||
|
|
||||||
|
.. _sequence protocols:
|
||||||
|
http://docs.python.org/lib/typesseq.html
|
||||||
|
|
||||||
|
.. [#grammar]
|
||||||
|
http://www.python.org/doc/current/ref/function.html
|
||||||
|
|
||||||
|
|
||||||
|
Copyright
|
||||||
|
=========
|
||||||
|
|
||||||
|
This document has been placed in the public domain.
|
||||||
|
|
||||||
|
|
||||||
|
..
|
||||||
|
Local Variables:
|
||||||
|
mode: indented-text
|
||||||
|
indent-tabs-mode: nil
|
||||||
|
sentence-end-double-space: t
|
||||||
|
fill-column: 70
|
||||||
|
coding: utf-8
|
||||||
|
End:
|
Loading…
Reference in New Issue