2006-12-22 10:46:01 -05:00
|
|
|
|
PEP: 3107
|
|
|
|
|
Title: Function Annotations
|
|
|
|
|
Version: $Revision$
|
|
|
|
|
Last-Modified: $Date$
|
|
|
|
|
Author: Collin Winter <collinw@gmail.com>,
|
2006-12-27 23:59:16 -05:00
|
|
|
|
Tony Lownds <tony@lownds.com>
|
2007-09-08 17:25:03 -04:00
|
|
|
|
Status: Final
|
2006-12-22 10:46:01 -05:00
|
|
|
|
Type: Standards Track
|
|
|
|
|
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
|
2007-01-04 13:19:54 -05:00
|
|
|
|
function's parameters and return values, a variety of tools
|
|
|
|
|
and libraries have appeared to fill this gap. Some
|
2006-12-22 10:46:01 -05:00
|
|
|
|
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
|
2006-12-27 23:59:16 -05:00
|
|
|
|
these expressions available as described in `Accessing Function
|
|
|
|
|
Annotations`_ below.
|
2006-12-22 10:46:01 -05:00
|
|
|
|
|
|
|
|
|
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
|
2006-12-23 01:10:01 -05:00
|
|
|
|
something like::
|
2006-12-22 10:46:01 -05:00
|
|
|
|
|
|
|
|
|
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
|
2006-12-23 01:10:01 -05:00
|
|
|
|
own; meaning comes from third-party libraries alone.
|
2006-12-22 10:46:01 -05:00
|
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Syntax
|
|
|
|
|
======
|
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
----------
|
|
|
|
|
|
|
|
|
|
Annotations for parameters take the form of optional expressions that
|
2007-01-04 13:19:54 -05:00
|
|
|
|
follow the parameter name::
|
2006-12-22 10:46:01 -05:00
|
|
|
|
|
2007-01-04 13:19:54 -05:00
|
|
|
|
def foo(a: expression, b: expression = 5):
|
2006-12-22 10:46:01 -05:00
|
|
|
|
...
|
|
|
|
|
|
|
|
|
|
In pseudo-grammar, parameters now look like ``identifier [:
|
2006-12-27 23:59:16 -05:00
|
|
|
|
expression] [= expression]``. That is, annotations always precede a
|
|
|
|
|
parameter's default value and both 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
|
2007-01-04 13:19:54 -05:00
|
|
|
|
expressions are evaluated when the function definition is executed,
|
|
|
|
|
just like default values.
|
2006-12-22 10:46:01 -05:00
|
|
|
|
|
|
|
|
|
Annotations for excess parameters (i.e., ``*args`` and ``**kwargs``)
|
2007-01-04 13:19:54 -05:00
|
|
|
|
are indicated similarly::
|
2006-12-22 10:46:01 -05:00
|
|
|
|
|
2007-01-04 13:19:54 -05:00
|
|
|
|
def foo(*args: expression, **kwargs: expression):
|
2006-12-22 10:46:01 -05:00
|
|
|
|
...
|
2007-01-04 13:19:54 -05:00
|
|
|
|
|
|
|
|
|
Annotations for nested parameters always follow the name of the
|
|
|
|
|
parameter, not the last parenthesis. Annotating all parameters of a
|
|
|
|
|
nested parameter is not required::
|
2006-12-22 10:46:01 -05:00
|
|
|
|
|
2007-01-04 13:19:54 -05:00
|
|
|
|
def foo((x1, y1: expression),
|
|
|
|
|
(x2: expression, y2: expression)=(None, None)):
|
2006-12-22 10:46:01 -05:00
|
|
|
|
...
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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::
|
|
|
|
|
|
2007-01-04 13:19:54 -05:00
|
|
|
|
def sum() -> expression:
|
2006-12-22 10:46:01 -05:00
|
|
|
|
...
|
|
|
|
|
|
2007-01-04 13:19:54 -05:00
|
|
|
|
That is, the parameter list can now be followed by a literal ``->``
|
|
|
|
|
and a Python expression. Like the annotations for parameters, this
|
2006-12-22 10:46:01 -05:00
|
|
|
|
expression will be evaluated when the function definition is executed.
|
|
|
|
|
|
2006-12-27 23:59:16 -05:00
|
|
|
|
The grammar for function definitions [#grammar]_ is now::
|
|
|
|
|
|
|
|
|
|
decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE
|
|
|
|
|
decorators: decorator+
|
|
|
|
|
funcdef: [decorators] 'def' NAME parameters ['->' test] ':' suite
|
|
|
|
|
parameters: '(' [typedargslist] ')'
|
|
|
|
|
typedargslist: ((tfpdef ['=' test] ',')*
|
|
|
|
|
('*' [tname] (',' tname ['=' test])* [',' '**' tname]
|
|
|
|
|
| '**' tname)
|
|
|
|
|
| tfpdef ['=' test] (',' tfpdef ['=' test])* [','])
|
|
|
|
|
tname: NAME [':' test]
|
|
|
|
|
tfpdef: tname | '(' tfplist ')'
|
|
|
|
|
tfplist: tfpdef (',' tfpdef)* [',']
|
|
|
|
|
|
|
|
|
|
Lambda
|
|
|
|
|
------
|
|
|
|
|
|
|
|
|
|
``lambda``'s syntax does not support annotations. The syntax of
|
|
|
|
|
``lambda`` could be changed to support annotations, by requiring
|
2007-01-04 13:19:54 -05:00
|
|
|
|
parentheses around the parameter list. However it was decided
|
2006-12-27 23:59:16 -05:00
|
|
|
|
[#lambda]_ not to make this change because:
|
|
|
|
|
|
|
|
|
|
1. It would be an incompatible change.
|
|
|
|
|
2. Lambda's are neutered anyway.
|
|
|
|
|
3. The lambda can always be changed to a function.
|
2006-12-22 10:46:01 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Accessing Function Annotations
|
|
|
|
|
==============================
|
|
|
|
|
|
|
|
|
|
Once compiled, a function's annotations are available via the
|
2006-12-27 23:59:16 -05:00
|
|
|
|
function's ``func_annotations`` attribute. This attribute is
|
2007-01-05 11:59:58 -05:00
|
|
|
|
a mutable dictionary, mapping parameter names to an object
|
|
|
|
|
representing the evaluated annotation expression
|
2006-12-22 10:46:01 -05:00
|
|
|
|
|
2006-12-27 23:59:16 -05:00
|
|
|
|
There is a special key in the ``func_annotations`` mapping,
|
2007-01-04 13:19:54 -05:00
|
|
|
|
``"return"``. This key is present only if an annotation was supplied
|
2006-12-27 23:59:16 -05:00
|
|
|
|
for the function's return value.
|
2006-12-22 10:46:01 -05:00
|
|
|
|
|
|
|
|
|
For example, the following annotation::
|
|
|
|
|
|
2007-01-04 13:19:54 -05:00
|
|
|
|
def foo(a: 'x', b: 5 + 6, c: list) -> max(2, 9):
|
2006-12-22 10:46:01 -05:00
|
|
|
|
...
|
|
|
|
|
|
2006-12-27 23:59:16 -05:00
|
|
|
|
would result in a ``func_annotation`` mapping of ::
|
2006-12-22 10:46:01 -05:00
|
|
|
|
|
2006-12-27 23:59:16 -05:00
|
|
|
|
{'a': 'x',
|
2006-12-22 10:46:01 -05:00
|
|
|
|
'b': 11,
|
|
|
|
|
'c': list,
|
2007-01-04 13:19:54 -05:00
|
|
|
|
'return': 9}
|
2006-12-22 10:46:01 -05:00
|
|
|
|
|
|
|
|
|
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``.
|
|
|
|
|
|
2007-01-05 11:59:58 -05:00
|
|
|
|
``func_annotations`` is an empty, mutable dictionary if there are no
|
|
|
|
|
annotations on the function or if the functions was created from
|
|
|
|
|
a ``lambda`` expression.
|
2006-12-27 23:59:16 -05:00
|
|
|
|
|
2007-01-04 13:19:54 -05:00
|
|
|
|
Use Cases
|
|
|
|
|
=========
|
|
|
|
|
|
|
|
|
|
In the course of discussing annotations, a number of use-cases have
|
|
|
|
|
been raised. Some of these are presented here, grouped by what kind
|
|
|
|
|
of information they convey. Also included are examples of existing
|
|
|
|
|
products and packages that could make use of annotations.
|
|
|
|
|
|
|
|
|
|
* Providing typing information
|
|
|
|
|
|
|
|
|
|
+ Type checking ([#typecheck]_, [#maxime]_)
|
|
|
|
|
+ Let IDEs show what types a function expects and returns ([#idle]_)
|
|
|
|
|
+ Function overloading / generic functions ([#scaling]_)
|
|
|
|
|
+ Foreign-language bridges ([#jython]_, [#ironpython]_)
|
|
|
|
|
+ Adaptation ([#adaptationpost]_, [#pyprotocols]_)
|
|
|
|
|
+ Predicate logic functions
|
|
|
|
|
+ Database query mapping
|
|
|
|
|
+ RPC parameter marshaling ([#rpyc]_)
|
|
|
|
|
|
|
|
|
|
* Other information
|
|
|
|
|
|
|
|
|
|
+ Documentation for parameters and return values ([#pydoc]_)
|
|
|
|
|
|
2006-12-27 23:59:16 -05:00
|
|
|
|
|
|
|
|
|
Standard Library
|
|
|
|
|
================
|
|
|
|
|
|
|
|
|
|
pydoc and inspect
|
|
|
|
|
-----------------
|
|
|
|
|
|
|
|
|
|
The ``pydoc`` module should display the function annotations when
|
2007-01-04 13:19:54 -05:00
|
|
|
|
displaying help for a function. The ``inspect`` module should change
|
2006-12-27 23:59:16 -05:00
|
|
|
|
to support annotations.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Relation to Other PEPs
|
|
|
|
|
======================
|
|
|
|
|
|
|
|
|
|
Function Signature Objects [#pep-362]_
|
|
|
|
|
--------------------------------------
|
|
|
|
|
|
|
|
|
|
Function Signature Objects should expose the function's annotations.
|
|
|
|
|
The ``Parameter`` object may change or other changes may be warranted.
|
|
|
|
|
|
2006-12-22 10:46:01 -05:00
|
|
|
|
|
|
|
|
|
Implementation
|
|
|
|
|
==============
|
|
|
|
|
|
2007-02-05 21:39:18 -05:00
|
|
|
|
A reference implementation has been checked into the p3yk branch
|
|
|
|
|
as revision 53170 [#implementation]_.
|
2006-12-22 10:46:01 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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
|
2007-01-04 13:19:54 -05:00
|
|
|
|
left to third-party libraries. ([#threadimmlist]_,
|
|
|
|
|
[#threadmixing]_, [#emphasistpls]_).
|
|
|
|
|
|
|
|
|
|
+ Despite yet more discussion, it was decided not to standardize
|
|
|
|
|
a mechanism for annotation interoperability. Standardizing
|
|
|
|
|
interoperability conventions at this point would be premature.
|
|
|
|
|
We would rather let these conventions develop organically, based
|
|
|
|
|
on real-world usage and necessity, than try to force all users
|
|
|
|
|
into some contrived scheme. ([#interop0]_, [#interop1]_,
|
|
|
|
|
[#interop2]_).
|
2006-12-22 10:46:01 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
References and Footnotes
|
|
|
|
|
========================
|
|
|
|
|
|
|
|
|
|
.. [#functerm] Unless specifically stated, "function" is generally
|
|
|
|
|
used as a synonym for "callable" throughout this document.
|
|
|
|
|
|
|
|
|
|
.. [#rejectgensyn]
|
|
|
|
|
http://mail.python.org/pipermail/python-3000/2006-May/002103.html
|
|
|
|
|
|
2007-01-04 13:19:54 -05:00
|
|
|
|
.. [#typecheck]
|
2006-12-22 10:46:01 -05:00
|
|
|
|
http://oakwinter.com/code/typecheck/
|
|
|
|
|
|
2007-01-04 13:19:54 -05:00
|
|
|
|
.. [#maxime]
|
2006-12-22 10:46:01 -05:00
|
|
|
|
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]
|
2007-02-05 21:39:18 -05:00
|
|
|
|
http://svn.python.org/view?rev=53170&view=rev
|
2006-12-22 10:46:01 -05:00
|
|
|
|
|
|
|
|
|
.. [#grammar]
|
2008-10-02 08:51:05 -04:00
|
|
|
|
http://docs.python.org/reference/compound_stmts.html#function-definitions
|
2006-12-22 10:46:01 -05:00
|
|
|
|
|
2006-12-27 23:59:16 -05:00
|
|
|
|
.. [#lambda]
|
|
|
|
|
http://mail.python.org/pipermail/python-3000/2006-May/001613.html
|
|
|
|
|
|
|
|
|
|
.. [#pep-362]
|
|
|
|
|
http://www.python.org/dev/peps/pep-0362/
|
2007-01-04 13:19:54 -05:00
|
|
|
|
|
|
|
|
|
.. [#interop0]
|
|
|
|
|
http://mail.python.org/pipermail/python-3000/2006-August/002895.html
|
|
|
|
|
|
|
|
|
|
.. [#interop1]
|
|
|
|
|
http://mail.python.org/pipermail/python-ideas/2007-January/000032.html
|
2006-12-27 23:59:16 -05:00
|
|
|
|
|
2007-01-04 13:19:54 -05:00
|
|
|
|
.. [#interop2]
|
|
|
|
|
http://mail.python.org/pipermail/python-list/2006-December/420645.html
|
|
|
|
|
|
|
|
|
|
.. [#idle]
|
|
|
|
|
http://www.python.org/idle/doc/idle2.html#Tips
|
|
|
|
|
|
|
|
|
|
.. [#jython]
|
|
|
|
|
http://www.jython.org/Project/index.html
|
|
|
|
|
|
|
|
|
|
.. [#ironpython]
|
|
|
|
|
http://www.codeplex.com/Wiki/View.aspx?ProjectName=IronPython
|
|
|
|
|
|
|
|
|
|
.. [#pyprotocols]
|
|
|
|
|
http://peak.telecommunity.com/PyProtocols.html
|
|
|
|
|
|
|
|
|
|
.. [#adaptationpost]
|
|
|
|
|
http://www.artima.com/weblogs/viewpost.jsp?thread=155123
|
|
|
|
|
|
|
|
|
|
.. [#scaling]
|
|
|
|
|
http://www-128.ibm.com/developerworks/library/l-cppeak2/
|
|
|
|
|
|
|
|
|
|
.. [#rpyc]
|
|
|
|
|
http://rpyc.wikispaces.com/
|
|
|
|
|
|
|
|
|
|
.. [#pydoc]
|
2008-10-02 08:40:49 -04:00
|
|
|
|
http://docs.python.org/library/pydoc.html
|
2006-12-27 23:59:16 -05:00
|
|
|
|
|
2006-12-22 10:46:01 -05:00
|
|
|
|
|
|
|
|
|
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:
|