[Python-Dev] pep 362 - 5th edition (original) (raw)

Nick Coghlan ncoghlan at gmail.com
Wed Jun 20 02:39:34 CEST 2012


On Wed, Jun 20, 2012 at 3:53 AM, Yury Selivanov <yselivanov.ml at gmail.com> wrote:

On 2012-06-19, at 1:03 PM, Ethan Furman wrote:

At some point it was suggested that Signature be put in provisionally so we could modify the API if needed -- are we doing that? Well, it doesn't have much of an API right now (just few methods)

Right, provisional API status is a fairly blunt instrument that we should only use if we can't find any other way to allow the standard library to progress.

In this particular case, we have a superior alternative: distill the API down to the bare minimum that is needed to provide a more robust, cross-implementation format for describing callable signatures. We can then implement that bare minimum API for 3.3 as the foundation for higher level layered APIs that offer more flexibility, and/or capture more information about the callables.

Further comments on the PEP and implementation:

  1. The PEP should specify the constructor signatures for Signature and Parameter objects (I'd also prefer it if "kind" was permitted as a positional argument)

  2. The constructor for Parameter objects should require that names for positional-only parameters start with "<" and end with ">" to ensure they can always be distinguished from standard parameters in signature string representations and in BoundArguments.parameters

  3. The standard Signature constructor should accept an iterable of Parameter objects directly (with the return annotation as an optional keyword-only "annotation" argument) and enforce the following constraints:

  1. The current Signature constructor should become a "from_function" class method

With these changes, the following would become straightforward:

>>> def f1(a): pass
>>> str(signature(f1))
(a)
>>> def f2(*args): a, = args
>>> f.__signature__ = Signature([Parameter("<a>",

Parameter.POSITIONAL_ONLY]) >>> str(signature(f2)) () >>> def f3(*args): a, = args >>> f.signature = Signature([Parameter(None, Parameter.POSITIONAL_ONLY]) >>> str(signature(f3)) (<0>)

  1. Given the updated constructor signature, we can revisit the question of immutable signature objects (even just using read-only properties for public attributes and exposing a dict proxy for the parameter list). Instead of mutating the parameter list, you would instead write code like: new_sig = Signature(old_sig.parameters[1:])

In my opinion, that's a much nicer approach than copying an existing signature object and mutating it.

  1. I think "return_annotation" can safely be abbreviated to just "annotation". The fact it is on the Signature object rather than an individual parameter is enough to identify it as the return annotation.

  2. The idea of immutable Signature objects does highlight an annoyance with the "attribute may be missing" style APIs. To actually duplicate a signature correctly, including its return annotation (and assuming the attribute is renamed), you would have to do something like:

    try: note = {"annotation": old_sig.annotation} except AttributeError: note = {} new_sig = Signature(old_sig.parameters[1:], **note)

There's an alternative approach to optional attributes that's often easier to work with: expose them as containers. In this case, since we want to make them easy to pass as keyword-only arguments, one way to achieve that would be expose an "optional" attribute on both Signature and Parameter objects. Then the above would be written as:

new_sig = Signature(old_sig.parameters[1:], **old_sig.optional)

And copying a Parameter would be: new_param = Parameter("new name", old_param.kind, **old_param.optional)

If we even keep that at all for the initial version of the API, the direct "default" and "annotation" attributes would just be read-only properties that accessed the "optional" container (reporting AttributeError if the corresponding attribute was missing)

  1. Not essential, but I suggest moving most of the parameter formatting details to a Parameter.str method

  2. The PEP should explicitly note that we're taking a deliberately strict approach to the notion of signature and parameter equivalence by assuming that all parameter names have semantic significance. Looser checks that ignore the names of positional and variable keyword parameters can be handled with Signature.bind() or by implementing custom key or comparison functions.

  3. Similar to the discussion of convenience properties on Signature objects themselves, I now think we should drop the "args" and "kwargs" properties from the initial version of BoundArguments. Instead, I propose the following attributes:

Cheers, Nick.

-- Nick Coghlan   |   ncoghlan at gmail.com   |   Brisbane, Australia



More information about the Python-Dev mailing list