[Python-checkins] peps: The latest changes from Yury Selivanov. I can almost taste the acceptance!
larry.hastings
python-checkins at python.org
Thu Jun 21 10:44:33 CEST 2012
http://hg.python.org/peps/rev/1edf1cecae7d
changeset: 4472:1edf1cecae7d
user: Larry Hastings <larry at hastings.org>
date: Thu Jun 21 01:44:15 2012 -0700
summary:
The latest changes from Yury Selivanov. I can almost taste the acceptance!
files:
pep-0362.txt | 159 +++++++++++++++++++++++++++++++-------
1 files changed, 128 insertions(+), 31 deletions(-)
diff --git a/pep-0362.txt b/pep-0362.txt
--- a/pep-0362.txt
+++ b/pep-0362.txt
@@ -42,23 +42,58 @@
A Signature object has the following public attributes and methods:
* return_annotation : object
- The annotation for the return type of the function if specified.
- If the function has no annotation for its return type, this
- attribute is not set.
+ The "return" annotation for the function. If the function
+ has no "return" annotation, this attribute is not set.
+
* parameters : OrderedDict
An ordered mapping of parameters' names to the corresponding
- Parameter objects (keyword-only arguments are in the same order
- as listed in ``code.co_varnames``).
+ Parameter objects.
+
* bind(\*args, \*\*kwargs) -> BoundArguments
Creates a mapping from positional and keyword arguments to
parameters. Raises a ``TypeError`` if the passed arguments do
not match the signature.
+
* bind_partial(\*args, \*\*kwargs) -> BoundArguments
Works the same way as ``bind()``, but allows the omission
of some required arguments (mimics ``functools.partial``
behavior.) Raises a ``TypeError`` if the passed arguments do
not match the signature.
+* replace(parameters, \*, return_annotation) -> Signature
+ Creates a new Signature instance based on the instance
+ ``replace`` was invoked on. It is possible to pass different
+ ``parameters`` and/or ``return_annotation`` to override the
+ corresponding properties of the base signature. To remove
+ ``return_annotation`` from the copied ``Signature``, pass in
+ ``Signature.empty``.
+
+Signature objects are immutable. Use ``Signature.replace()`` to
+make a modified copy:
+::
+
+ >>> sig = signature(foo)
+ >>> new_sig = sig.replace(return_annotation="new return annotation")
+ >>> new_sig is not sig
+ True
+ >>> new_sig.return_annotation == sig.return_annotation
+ True
+ >>> new_sig.parameters == sig.parameters
+ True
+
+There are two ways to instantiate a Signature class:
+
+* Signature(parameters, *, return_annotation)
+ Default Signature constructor. Accepts an optional sequence
+ of ``Parameter`` objects, and an optional ``return_annotation``.
+ Parameters sequence is validated to check that there are no
+ parameters with duplicate names, and that the parameters
+ are in the right order, i.e. positional-only first, then
+ positional-or-keyword, etc.
+* Signature.from_function(function)
+ Returns a Signature object reflecting the signature of the
+ function passed in.
+
It's possible to test Signatures for equality. Two signatures are
equal when their parameters are equal, their positional and
positional-only parameters appear in the same order, and they
@@ -67,9 +102,14 @@
Changes to the Signature object, or to any of its data members,
do not affect the function itself.
-Signature also implements ``__str__`` and ``__copy__`` methods.
-The latter creates a shallow copy of Signature, with all Parameter
-objects copied as well.
+Signature also implements ``__str__``:
+::
+
+ >>> str(Signature.from_function((lambda *args: None)))
+ '(*args)'
+
+ >>> str(Signature())
+ '()'
Parameter Object
@@ -80,20 +120,22 @@
propose a rich Parameter object designed to represent any possible
function parameter.
-The structure of the Parameter object is:
+A Parameter object has the following public attributes and methods:
* name : str
- The name of the parameter as a string.
+ The name of the parameter as a string. Must be a valid
+ python identifier name (with the exception of ``POSITIONAL_ONLY``
+ parameters, which can have it set to ``None``.)
* default : object
- The default value for the parameter, if specified. If the
- parameter has no default value, this attribute is not set.
+ The default value for the parameter. If the parameter has no
+ default value, this attribute is not set.
* annotation : object
- The annotation for the parameter if specified. If the
- parameter has no annotation, this attribute is not set.
+ The annotation for the parameter. If the parameter has no
+ annotation, this attribute is not set.
-* kind : str
+* kind
Describes how argument values are bound to the parameter.
Possible values:
@@ -101,7 +143,7 @@
as a positional argument.
Python has no explicit syntax for defining positional-only
- parameters, but many builtin and extension module functions
+ parameters, but many built-in and extension module functions
(especially those that accept only one or two parameters)
accept them.
@@ -124,9 +166,30 @@
that aren't bound to any other parameter. This corresponds
to a "\*\*kwds" parameter in a Python function definition.
+* replace(\*, name, kind, default, annotation) -> Parameter
+ Creates a new Parameter instance based on the instance
+ ``replaced`` was invoked on. To override a Parameter
+ attribute, pass the corresponding argument. To remove
+ an attribute from a ``Parameter``, pass ``Parameter.empty``.
+
+
Two parameters are equal when they have equal names, kinds, defaults,
and annotations.
+Parameter objects are immutable. Instead of modifying a Parameter object,
+you can use ``Parameter.replace()`` to create a modified copy like so:
+::
+
+ >>> param = Parameter('foo', Parameter.KEYWORD_ONLY, default=42)
+ >>> str(param)
+ 'foo=42'
+
+ >>> str(param.replace())
+ 'foo=42'
+
+ >>> str(param.replace(default=Parameter.empty, annotation='spam'))
+ "foo:'spam'"
+
BoundArguments Object
=====================
@@ -138,7 +201,8 @@
* arguments : OrderedDict
An ordered, mutable mapping of parameters' names to arguments' values.
- Does not contain arguments' default values.
+ Contains only explicitly bound arguments. Arguments for
+ which ``bind()`` relied on a default value are skipped.
* args : tuple
Tuple of positional arguments values. Dynamically computed from
the 'arguments' attribute.
@@ -159,6 +223,23 @@
ba = sig.bind(10, b=20)
test(*ba.args, **ba.kwargs)
+Arguments which could be passed as part of either ``*args`` or ``**kwargs``
+will be included only in the ``BoundArguments.args`` attribute. Consider the
+following example:
+::
+
+ def test(a=1, b=2, c=3):
+ pass
+
+ sig = signature(test)
+ ba = sig.bind(a=10, c=13)
+
+ >>> ba.args
+ (10,)
+
+ >>> ba.kwargs:
+ {'c': 13}
+
Implementation
==============
@@ -172,7 +253,7 @@
- If the object is not callable - raise a TypeError
- If the object has a ``__signature__`` attribute and if it
- is not ``None`` - return a shallow copy of it
+ is not ``None`` - return it
- If it has a ``__wrapped__`` attribute, return
``signature(object.__wrapped__)``
@@ -180,12 +261,9 @@
- If the object is a an instance of ``FunctionType`` construct
and return a new ``Signature`` for it
- - If the object is a method or a classmethod, construct and return
- a new ``Signature`` object, with its first parameter (usually
- ``self`` or ``cls``) removed
-
- - If the object is a staticmethod, construct and return
- a new ``Signature`` object
+ - If the object is a method, construct and return a new ``Signature``
+ object, with its first parameter (usually ``self`` or ``cls``)
+ removed
- If the object is an instance of ``functools.partial``, construct
a new ``Signature`` from its ``partial.func`` attribute, and
@@ -196,15 +274,15 @@
- If the object's type has a ``__call__`` method defined in
its MRO, return a Signature for it
- - If the object has a ``__new__`` method defined in its class,
+ - If the object has a ``__new__`` method defined in its MRO,
return a Signature object for it
- - If the object has a ``__init__`` method defined in its class,
+ - If the object has a ``__init__`` method defined in its MRO,
return a Signature object for it
- Return ``signature(object.__call__)``
-Note, that the ``Signature`` object is created in a lazy manner, and
+Note that the ``Signature`` object is created in a lazy manner, and
is not automatically cached. If, however, the Signature object was
explicitly cached by the user, ``signature()`` returns a new shallow copy
of it on each invocation.
@@ -236,11 +314,21 @@
----------------------------------------
Some functions may not be introspectable in certain implementations of
-Python. For example, in CPython, builtin functions defined in C provide
+Python. For example, in CPython, built-in functions defined in C provide
no metadata about their arguments. Adding support for them is out of
scope for this PEP.
+Signature and Parameter equivalence
+-----------------------------------
+
+We assume that parameter names have semantic significance--two
+signatures are equal only when their corresponding parameters have
+the exact same names. Users who want looser equivalence tests, perhaps
+ignoring names of VAR_KEYWORD or VAR_POSITIONAL parameters, will
+need to implement those themselves.
+
+
Examples
========
@@ -270,6 +358,10 @@
def __call__(self, a, b, *, c) -> tuple:
return a, b, c
+ @classmethod
+ def spam(cls, a):
+ return a
+
def shared_vars(*shared_args):
"""Decorator factory that defines shared variables that are
@@ -280,10 +372,12 @@
def wrapper(*args, **kwds):
full_args = shared_args + args
return f(*full_args, **kwds)
+
# Override signature
- sig = wrapper.__signature__ = signature(f)
- for __ in shared_args:
- sig.parameters.popitem(last=False)
+ sig = signature(f)
+ sig = sig.replace(tuple(sig.parameters.values())[1:])
+ wrapper.__signature__ = sig
+
return wrapper
return decorator
@@ -313,6 +407,9 @@
>>> format_signature(Foo().__call__)
'(a, b, *, c) -> tuple'
+ >>> format_signature(Foo.spam)
+ '(a)'
+
>>> format_signature(partial(Foo().__call__, 1, c=3))
'(b, *, c=3) -> tuple'
--
Repository URL: http://hg.python.org/peps
More information about the Python-checkins
mailing list