python-peps/pep-0362.txt

265 lines
10 KiB
Plaintext
Raw Normal View History

2006-08-21 19:54:07 -04:00
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
2007-09-06 22:35:14 -04:00
Post-History: 05-Sep-2007
2006-08-21 19:54:07 -04:00
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.
2006-08-21 19:54:07 -04:00
This PEP proposes an object representation for function signatures.
This should help facilitate introspection on functions for various
uses. The introspection information contains all possible information
about the parameters in a signature (including Python 3.0 features).
2006-08-21 19:54:07 -04:00
2007-09-06 22:19:39 -04:00
This object, though, is not meant to replace existing ways of
introspection on a function's signature. The current solutions are
there to make Python's execution work in an efficient manner. The
proposed object representation is only meant to help make application
code have an easier time to query a function on its signature.
2006-08-21 19:54:07 -04:00
Purpose
=======
An object representation of a function's call signature should provide
an easy way to introspect what a function expects as arguments. It
does not need to be a "live" representation, though; the signature can
be inferred once and stored without changes to the signature object
representation affecting the function it represents (but this is an
2007-09-07 21:07:58 -04:00
`Open Issues`_).
Indirecation of signature introspection can also occur. If a
decorator took a decorated function's signature object and set it on
the decorating function then introspection could be redirected to what
is actually expected instead of the typical ``*args, **kwargs``
signature of decorating functions.
2006-08-21 19:54:07 -04:00
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.
2006-08-21 19:54:07 -04:00
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,
2006-09-02 13:21:40 -04:00
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.
* has_annotation : bool
Signifies whether the function has an annotation for the return
type.
* annotation : object
If present, the attribute is set to the annotation for the return
type of the function.
* 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.
2006-08-21 19:54:07 -04:00
The Signature object is stored in the ``__signature__`` attribute of
2007-09-06 22:19:39 -04:00
a function. When it is to be created is discussed in
`Open Issues`_.
2006-08-21 19:54:07 -04:00
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.
2006-08-21 19:54:07 -04:00
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).
2006-08-21 19:54:07 -04:00
The structure of the Parameter object is:
* name : (str | tuple(str))
2006-08-21 19:54:07 -04:00
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
2006-08-21 19:54:07 -04:00
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
2006-08-21 19:54:07 -04:00
True if the parameter has a default value, else False.
* default_value : object
2006-08-21 19:54:07 -04:00
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.
2006-08-21 19:54:07 -04:00
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
2007-09-06 22:19:39 -04:00
exists, else it creates the Signature object for the
function and sets ``__signature__``. For methods this is stored
directly on the im_func function object since that is what decorators
work with.
2006-08-21 19:54:07 -04:00
Open Issues
===========
When to construct the Signature object?
2006-08-21 19:54:07 -04:00
---------------------------------------
The Signature object can either be created in an eager or lazy
2006-08-21 19:54:07 -04:00
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
2006-08-21 19:54:07 -04:00
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.
2006-08-21 19:54:07 -04:00
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``).
2006-08-21 19:54:07 -04:00
2007-09-06 22:19:39 -04:00
Remove ``has_*`` attributes?
----------------------------
If an EAFP approach to the API is taken, both ``has_annotation`` and
``has_default`` are unneeded as the respective ``annotation`` and
``default_value`` attributes are simply not set. It's simply a
question of whether to have a EAFP or LBYL interface.
Have ``var_args`` and ``_var_kw_args`` default to ``None``?
------------------------------------------------------------
It has been suggested by Fred Drake that these two attributes have a
value of ``None`` instead of empty strings when they do not exist.
The answer to this question will influence what the defaults are for
other attributes as well.
2007-09-06 22:19:39 -04:00
Deprecate ``inspect.getargspec()`` and ``.formatargspec()``?
-------------------------------------------------------------
Since the Signature object replicates the use of ``getargspec()``
from the ``inspect`` module it might make sense to deprecate it in
2.6. ``formatargspec()`` could also go if Signature objects gained a
__str__ representation.
Issue with that is types such as ``int``, when used as annotations,
2007-09-06 22:42:45 -04:00
do not lend themselves for output (e.g., ``"<type 'int'>"`` is the
2007-09-06 22:19:39 -04:00
string represenation for ``int``). The repr representation of types
would need to change in order to make this reasonable.
Have the objects be "live"?
---------------------------
Jim Jewett pointed out that Signature and Parameter objects could be
"live". That would mean requesting information would be done on the
fly instead of caching it on the objects. It would also allow for
mutating the function if the Signature or Parameter objects were
mutated.
References
==========
.. [#impl] pep362 directory in Python's sandbox
(http://svn.python.org/view/sandbox/trunk/pep362/)
2006-08-21 19:54:07 -04: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: