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
|
2007-06-19 00:20:07 -04:00
|
|
|
|
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,
|
2006-08-22 18:03:11 -04:00
|
|
|
|
including that for functions and methods (for the rest of this PEP the
|
|
|
|
|
word "function" refers to both functions and methods). Taking a
|
2007-02-26 10:30:51 -05:00
|
|
|
|
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.
|
2007-02-26 10:30:51 -05:00
|
|
|
|
This should help facilitate introspection on functions for various
|
2007-09-07 21:07:12 -04:00
|
|
|
|
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
|
|
|
|
|
2007-09-07 21:07:12 -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`_).
|
2007-09-07 21:07:12 -04:00
|
|
|
|
|
|
|
|
|
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
|
2007-02-26 10:30:51 -05:00
|
|
|
|
object. This object is to store a `Parameter object`_ for each
|
2006-12-30 01:17:05 -05:00
|
|
|
|
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:
|
|
|
|
|
|
2007-02-26 10:30:51 -05:00
|
|
|
|
* name : str
|
2006-08-22 18:03:11 -04:00
|
|
|
|
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.
|
2007-02-26 10:30:51 -05:00
|
|
|
|
* 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.
|
2007-11-16 23:20:22 -05:00
|
|
|
|
* return_annotation : object
|
2007-09-07 21:07:12 -04:00
|
|
|
|
If present, the attribute is set to the annotation for the return
|
|
|
|
|
type of the function.
|
2007-02-26 10:30:51 -05:00
|
|
|
|
* parameters : list(Parameter)
|
2006-12-30 01:17:05 -05:00
|
|
|
|
List of the parameters of the function as represented by
|
2007-02-26 10:30:51 -05:00
|
|
|
|
Parameter objects in the order of its definition (keyword-only
|
|
|
|
|
arguments are in the order listed by ``code.co_varnames``).
|
2007-11-16 21:36:40 -05:00
|
|
|
|
* bind(\*args, \*\*kwargs) -> dict(str, object)
|
2007-02-26 10:30:51 -05:00
|
|
|
|
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
|
|
|
|
|
2007-11-16 23:20:22 -05:00
|
|
|
|
Signature objects also have the following methods:
|
|
|
|
|
|
|
|
|
|
* __getitem__(self, key : str) -> Parameter
|
|
|
|
|
Returns the Parameter object for the named parameter.
|
|
|
|
|
* __iter__(self)
|
|
|
|
|
Returns an iterator that returns Parameter objects in their
|
|
|
|
|
sequential order based on their 'position' attribute.
|
|
|
|
|
|
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
|
2006-12-30 01:17:05 -05:00
|
|
|
|
`Open Issues`_.
|
2006-08-21 19:54:07 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Parameter Object
|
|
|
|
|
================
|
|
|
|
|
|
2007-02-26 10:30:51 -05:00
|
|
|
|
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
|
2007-02-26 10:30:51 -05:00
|
|
|
|
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:
|
|
|
|
|
|
2007-02-26 10:30:51 -05:00
|
|
|
|
* 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
|
2007-02-26 10:30:51 -05:00
|
|
|
|
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
|
2007-02-26 10:30:51 -05:00
|
|
|
|
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.
|
|
|
|
|
* default_value : object
|
2006-08-21 19:54:07 -04:00
|
|
|
|
The default value for the parameter, if present, else the
|
2007-11-16 23:20:22 -05:00
|
|
|
|
attribute does not exist.
|
2007-02-26 10:30:51 -05:00
|
|
|
|
* keyword_only : bool
|
|
|
|
|
True if the parameter is keyword-only, 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
|
|
|
|
|
==============
|
|
|
|
|
|
2007-02-26 10:30:51 -05:00
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
2007-11-16 23:20:22 -05:00
|
|
|
|
Examples
|
|
|
|
|
========
|
|
|
|
|
|
|
|
|
|
Annotation Checker
|
|
|
|
|
------------------
|
|
|
|
|
::
|
|
|
|
|
|
|
|
|
|
def quack_check(fxn):
|
|
|
|
|
"""Decorator to verify arguments and return value quack as they should.
|
|
|
|
|
|
|
|
|
|
Positional arguments.
|
|
|
|
|
>>> @quack_check
|
|
|
|
|
... def one_arg(x:int): pass
|
|
|
|
|
...
|
|
|
|
|
>>> one_arg(42)
|
|
|
|
|
>>> one_arg('a')
|
|
|
|
|
Traceback (most recent call last):
|
|
|
|
|
...
|
|
|
|
|
TypeError: 'a' does not quack like a <type 'int'>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*args
|
|
|
|
|
>>> @quack_check
|
|
|
|
|
... def var_args(*args:int): pass
|
|
|
|
|
...
|
|
|
|
|
>>> var_args(*[1,2,3])
|
|
|
|
|
>>> var_args(*[1,'b',3])
|
|
|
|
|
Traceback (most recent call last):
|
|
|
|
|
...
|
|
|
|
|
TypeError: *args contains a a value that does not quack like a <type 'int'>
|
|
|
|
|
|
|
|
|
|
**kwargs
|
|
|
|
|
>>> @quack_check
|
|
|
|
|
... def var_kw_args(**kwargs:int): pass
|
|
|
|
|
...
|
|
|
|
|
>>> var_kw_args(**{'a': 1})
|
|
|
|
|
>>> var_kw_args(**{'a': 'A'})
|
|
|
|
|
Traceback (most recent call last):
|
|
|
|
|
...
|
|
|
|
|
TypeError: **kwargs contains a value that does not quack like a <type 'int'>
|
|
|
|
|
|
|
|
|
|
Return annotations.
|
|
|
|
|
>>> @quack_check
|
|
|
|
|
... def returned(x) -> int: return x
|
|
|
|
|
...
|
|
|
|
|
>>> returned(42)
|
|
|
|
|
42
|
|
|
|
|
>>> returned('a')
|
|
|
|
|
Traceback (most recent call last):
|
|
|
|
|
...
|
|
|
|
|
TypeError: the return value 'a' does not quack like a <type 'int'>
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
# Get the signature; only needs to be calculated once.
|
|
|
|
|
sig = Signature(fxn)
|
|
|
|
|
def check(*args, **kwargs):
|
|
|
|
|
# Find out the variable -> value bindings.
|
|
|
|
|
bindings = sig.bind(*args, **kwargs)
|
|
|
|
|
# Check *args for the proper quack.
|
|
|
|
|
try:
|
|
|
|
|
duck = sig.var_annotations[sig.var_args]
|
|
|
|
|
except KeyError:
|
|
|
|
|
pass
|
|
|
|
|
else:
|
|
|
|
|
# Check every value in *args.
|
|
|
|
|
for value in bindings[sig.var_args]:
|
|
|
|
|
if not isinstance(value, duck):
|
|
|
|
|
raise TypeError("*%s contains a a value that does not "
|
|
|
|
|
"quack like a %r" %
|
|
|
|
|
(sig.var_args, duck))
|
|
|
|
|
# Remove it from the bindings so as to not check it again.
|
|
|
|
|
del bindings[sig.var_args]
|
|
|
|
|
# **kwargs.
|
|
|
|
|
try:
|
|
|
|
|
duck = sig.var_annotations[sig.var_kw_args]
|
|
|
|
|
except (KeyError, AttributeError):
|
|
|
|
|
pass
|
|
|
|
|
else:
|
|
|
|
|
# Check every value in **kwargs.
|
|
|
|
|
for value in bindings[sig.var_kw_args].values():
|
|
|
|
|
if not isinstance(value, duck):
|
|
|
|
|
raise TypeError("**%s contains a value that does not "
|
|
|
|
|
"quack like a %r" %
|
|
|
|
|
(sig.var_kw_args, duck))
|
|
|
|
|
# Remove from bindings so as to not check again.
|
|
|
|
|
del bindings[sig.var_kw_args]
|
|
|
|
|
# For each remaining variable ...
|
|
|
|
|
for var, value in bindings.items():
|
|
|
|
|
# See if an annotation was set.
|
|
|
|
|
try:
|
|
|
|
|
duck = sig[var].annotation
|
|
|
|
|
except AttributeError:
|
|
|
|
|
continue
|
|
|
|
|
# Check that the value quacks like it should.
|
|
|
|
|
if not isinstance(value, duck):
|
|
|
|
|
raise TypeError('%r does not quack like a %s' % (value, duck))
|
|
|
|
|
else:
|
|
|
|
|
# All the ducks quack fine; let the call proceed.
|
|
|
|
|
returned = fxn(*args, **kwargs)
|
|
|
|
|
# Check the return value.
|
|
|
|
|
try:
|
|
|
|
|
if not isinstance(returned, sig.return_annotation):
|
|
|
|
|
raise TypeError('the return value %r does not quack like '
|
|
|
|
|
'a %r' % (returned,
|
|
|
|
|
sig.return_annotation))
|
|
|
|
|
except AttributeError:
|
|
|
|
|
pass
|
|
|
|
|
return returned
|
|
|
|
|
# Full-featured version would set function metadata.
|
|
|
|
|
return check
|
|
|
|
|
|
|
|
|
|
|
2006-08-21 19:54:07 -04:00
|
|
|
|
Open Issues
|
|
|
|
|
===========
|
|
|
|
|
|
2007-02-26 10:30:51 -05:00
|
|
|
|
When to construct the Signature object?
|
2006-08-21 19:54:07 -04:00
|
|
|
|
---------------------------------------
|
|
|
|
|
|
2007-02-26 10:30:51 -05: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
|
2007-02-26 10:30:51 -05:00
|
|
|
|
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__``.
|
|
|
|
|
|
|
|
|
|
|
2006-12-30 01:17:05 -05:00
|
|
|
|
Should ``Signature.bind`` return Parameter objects as keys?
|
|
|
|
|
-----------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
Instead of returning a dict with keys consisting of the name of the
|
2007-02-26 10:30:51 -05:00
|
|
|
|
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).
|
2006-12-30 01:17:05 -05:00
|
|
|
|
|
|
|
|
|
|
2007-09-06 22:19:39 -04:00
|
|
|
|
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.
|
2007-09-07 21:07:12 -04:00
|
|
|
|
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.
|
|
|
|
|
|
|
|
|
|
|
2007-09-07 21:07:12 -04:00
|
|
|
|
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.
|
|
|
|
|
|
|
|
|
|
|
2007-02-26 10:30:51 -05:00
|
|
|
|
References
|
|
|
|
|
==========
|
2006-08-22 18:03:11 -04:00
|
|
|
|
|
2007-02-26 10:30:51 -05:00
|
|
|
|
.. [#impl] pep362 directory in Python's sandbox
|
|
|
|
|
(http://svn.python.org/view/sandbox/trunk/pep362/)
|
2006-12-30 01:17:05 -05:00
|
|
|
|
|
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:
|