194 lines
7.2 KiB
Plaintext
194 lines
7.2 KiB
Plaintext
PEP: 362
|
||
Title: Function Signature Object
|
||
Version: $Revision$
|
||
Last-Modified: $Date$
|
||
Author: Brett Cannon <brett@python.org>
|
||
Jiwon Seo <seojiwon@gmail.com>
|
||
Status: Draft
|
||
Type: Standards Track
|
||
Content-Type: text/x-rst
|
||
Created: 21-Aug-2006
|
||
Python-Version: 2.6
|
||
Post-History:
|
||
|
||
|
||
Abstract
|
||
========
|
||
|
||
Python has always supported powerful introspection capabilities,
|
||
including that for functions and methods (for the rest of this PEP the
|
||
word "function" refers to both functions and methods). Taking a
|
||
function object, you can fully reconstruct the function's signature.
|
||
Unfortunately it is a little unruly having to look at all the
|
||
different attributes to pull together complete information for a
|
||
function's signature.
|
||
|
||
This PEP proposes an object representation for function signatures.
|
||
This should help facilitate introspection on functions for various
|
||
usese (e.g., decorators). The introspection information contains all
|
||
possible information about the parameters in a signature (including
|
||
Python 3.0 features).
|
||
|
||
|
||
Signature Object
|
||
================
|
||
|
||
The overall signature of an object is represented by the Signature
|
||
object. This object is to store a `Parameter object`_ for each
|
||
parameter in the signature. It is also to store any information
|
||
about the function itself that is pertinent to the signature.
|
||
|
||
A Signature object has the following structure attributes:
|
||
|
||
* name : str
|
||
Name of the function. This is not fully qualified because
|
||
function objects for methods do not know the class they are
|
||
contained within. This makes functions and methods
|
||
indistinguishable from one another when passed to decorators,
|
||
preventing proper creation of a fully qualified name.
|
||
* var_args : str
|
||
Name of the variable positional parameter (i.e., ``*args``), if
|
||
present, or the empty string.
|
||
* var_kw_args : str
|
||
Name of the variable keyword parameter (i.e., ``**kwargs``), if
|
||
present, or the empty string.
|
||
* var_annotations: dict(str, object)
|
||
Dict that contains the annotations for the variable parameters.
|
||
The keys are of the variable parameter with values of the
|
||
annotation. If an annotation does not exist for a variable
|
||
parameter then the key does not exist in the dict.
|
||
* parameters : list(Parameter)
|
||
List of the parameters of the function as represented by
|
||
Parameter objects in the order of its definition (keyword-only
|
||
arguments are in the order listed by ``code.co_varnames``).
|
||
* bind(\*args, \*\*kwargs) -> dict(str, Parameter)
|
||
Create a mapping from arguments to parameters. The keys are the
|
||
names of the parameter that an argument maps to with the value
|
||
being the value the parameter would have if this function was
|
||
called with the given arguments.
|
||
|
||
The Signature object is stored in the ``__signature__`` attribute of
|
||
the function. When it is to be created is discussed in
|
||
`Open Issues`_.
|
||
|
||
|
||
Parameter Object
|
||
================
|
||
|
||
A function's signature is made up of several parameters. Python's
|
||
different kinds of parameters is quite large and rich and continues to
|
||
grow. Parameter objects represent any possible parameter.
|
||
|
||
Originally the plan was to represent parameters using a list of
|
||
parameter names on the Signature object along with various dicts keyed
|
||
on parameter names to disseminate the various pieces of information
|
||
one can know about a parameter. But the decision was made to
|
||
incorporate all information about a parameter in a single object so
|
||
as to make extending the information easier. This was originally put
|
||
forth by Talin and the preferred form of Guido (as discussed at the
|
||
2006 Google Sprint).
|
||
|
||
The structure of the Parameter object is:
|
||
|
||
* name : (str | tuple(str))
|
||
The name of the parameter as a string if it is not a tuple. If
|
||
the argument is a tuple then a tuple of strings is used.
|
||
* position : int
|
||
The position of the parameter within the signature of the
|
||
function (zero-indexed). For keyword-only parameters the position
|
||
value is arbitrary while not conflicting with positional
|
||
parameters. The suggestion of setting the attribute to None or -1
|
||
to represent keyword-only parameters was rejected to prevent
|
||
variable type usage and as a possible point of errors,
|
||
respectively.
|
||
* has_default : bool
|
||
True if the parameter has a default value, else False.
|
||
* default_value : object
|
||
The default value for the parameter, if present, else the
|
||
attribute does not exist. This is done so that the attribute is
|
||
not accidentally used if no default value is set as any default
|
||
value could be a legitimate default value itself.
|
||
* keyword_only : bool
|
||
True if the parameter is keyword-only, else False.
|
||
* has_annotation : bool
|
||
True if the parameter has an annotation, else False.
|
||
* annotation
|
||
Set to the annotation for the parameter. If ``has_annotation`` is
|
||
False then the attribute does not exist to prevent accidental use.
|
||
|
||
|
||
Implementation
|
||
==============
|
||
|
||
An implementation can be found in Python's sandbox [#impl]_.
|
||
There is a function named ``signature()`` which
|
||
returns the value stored on the ``__signature__`` attribute if it
|
||
exists, else it creates it bound to the Signature object for the
|
||
function. For methods this is stored directly on the im_func function
|
||
object since that is what decorators will work with.
|
||
|
||
|
||
Open Issues
|
||
===========
|
||
|
||
When to construct the Signature object?
|
||
---------------------------------------
|
||
|
||
The Signature object can either be created in an eager or lazy
|
||
fashion. In the eager situation, the object can be created during
|
||
creation of the function object. In the lazy situation, one would
|
||
pass a function object to a function and that would generate the
|
||
Signature object and store it to ``__signature__`` if
|
||
needed, and then return the value of ``__signature__``.
|
||
|
||
|
||
Should ``Signature.bind`` return Parameter objects as keys?
|
||
-----------------------------------------------------------
|
||
|
||
Instead of returning a dict with keys consisting of the name of the
|
||
parameters, would it be more useful to instead use Parameter
|
||
objects? The name of the argument can easily be retrieved from the
|
||
key (and the name would be used as the hash for a Parameter object).
|
||
|
||
|
||
Provide a mapping of parameter name to Parameter object?
|
||
--------------------------------------------------------
|
||
|
||
While providing access to the parameters in order is handy, it might
|
||
also be beneficial to provide a way to retrieve Parameter objects from
|
||
a Signature object based on the parameter's name. Which style of
|
||
access (sequential/iteration or mapping) will influence how the
|
||
parameters are stored internally and whether __getitem__ accepts
|
||
strings or integers.
|
||
|
||
One possible compromise is to have ``__getitem__`` provide mapping
|
||
support and have ``__iter__`` return Parameter objects based on their
|
||
``position`` attribute. This allows for getting the sequence of
|
||
Parameter objects easily by using the ``__iter__`` method on Signature
|
||
object along with the sequence constructor (e.g., ``list`` or
|
||
``tuple``).
|
||
|
||
|
||
References
|
||
==========
|
||
|
||
.. [#impl] pep362 directory in Python's sandbox
|
||
(http://svn.python.org/view/sandbox/trunk/pep362/)
|
||
|
||
|
||
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:
|