Update from Tony Lownds sent in private mail and to python-3000

This commit is contained in:
Neal Norwitz 2006-12-28 04:59:16 +00:00
parent 58bc5d3a66
commit 2cab42267d
1 changed files with 88 additions and 55 deletions

View File

@ -3,7 +3,7 @@ Title: Function Annotations
Version: $Revision$
Last-Modified: $Date$
Author: Collin Winter <collinw@gmail.com>,
Tony Lownds <tony@pagedna.com>
Tony Lownds <tony@lownds.com>
Status: Draft
Type: Standards Track
Requires: 362
@ -51,9 +51,8 @@ what annotations are and are not:
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.
these expressions available as 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
@ -98,38 +97,33 @@ 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
be a ``Mapping``::
follow the parameter name. This example indicates that parameters
'a' and 'c' should both be an ``int``, while parameter 'b' should
be a ``dict``::
def foo(a: Number, b: Mapping, c: Number = 5):
def foo(a: int, b: dict, c: int = 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.
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
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
``*args`` is flagged as a tuple of ``int``, and ``**kwargs`` is
marked as a dict whose keys are strings and whose values are of type
``Sequence``. ::
``str``::
def foo(*args: Number, **kwargs: Sequence):
def foo(*args: int, **kwargs: str):
...
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}):
def foo(*args: [int], **kwargs: {str: str}):
...
Only the first, however, has the BDFL's blessing [#blessedexcess]_ as
@ -142,68 +136,99 @@ 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:
def sum(*args: int) -> int:
...
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::
The grammar for function definitions [#grammar]_ is now::
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
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
parentheses around the parameter list. However it was decided
[#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.
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.
function's ``func_annotations`` attribute. 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.
There is a special key in the ``func_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:
def foo(a: 'x', b: 5 + 6, c: list) -> str:
...
would result in a ``__signature__.annotations`` mapping of ::
would result in a ``func_annotation`` mapping of ::
{'a': Number,
{'a': 'x',
'b': 11,
'c': list,
'return': String}
'return': str}
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``.
``func_annotations`` is an empty dictionary if no there are no
annotations on the function. ``func_annotations`` is always an empty
dictionary for functions created from ``lambda`` expressions.
Standard Library
================
pydoc and inspect
-----------------
The ``pydoc`` module should display the function annotations when
displaying help for a function. The ``inspect`` module should change
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.
Implementation
==============
A sample implementation has been provided [#implementation]_ by Tony
Lownds.
A sample implementation for the syntax changes has been provided
[#implementation]_ by Tony Lownds.
Rejected Proposals
@ -220,8 +245,8 @@ Rejected Proposals
+ 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]_)
left to third-party libraries. ([#threadimmlist]_,
[#threadmixing]_, [#emphasistpls]_)
References and Footnotes
@ -276,6 +301,13 @@ References and Footnotes
.. [#grammar]
http://www.python.org/doc/current/ref/function.html
.. [#lambda]
http://mail.python.org/pipermail/python-3000/2006-May/001613.html
.. [#pep-362]
http://www.python.org/dev/peps/pep-0362/
Copyright
=========
@ -291,3 +323,4 @@ This document has been placed in the public domain.
fill-column: 70
coding: utf-8
End: