[Python-Dev] PEP 362: 4th edition

Nick Coghlan ncoghlan at gmail.com
Sat Jun 16 17:27:39 CEST 2012


On Sat, Jun 16, 2012 at 1:56 PM, Jim J. Jewett <jimjjewett at gmail.com> wrote:
>
> Summary:
>
>    *Every* Parameter attribute is optional, even name.  (Think of
>    builtins, even if they aren't automatically supported yet.)
>    So go ahead and define some others that are sometimes useful.

No, that's not the right attitude to take when designing a new API.
Add only stuff we know is interesting and useful. Call YAGNI on
everything else. If we later decided we missed something, then we can
add it easily. If something we add up front turns out to be useless
(or, worse, an attractive nuisance), then it's a pain to eliminate.

For parameters, that list is only:

- kind
- name (should be given meaningful content, even for POSITIONAL_ONLY parameters)
- default (may be missing, since "None" is allowed as a default value)
- annotation (may be missing, since "None" is allowed as an annotation)

>    Instead of defining a BoundArguments class, just return a copy
>    of the Signature, with "value" attributes added to the Parameters.

No, the "BoundArguments" class is designed to be easy to feed to a
function call as f(*args, **kwds)

>    Use subclasses to distinguish the parameter kind.  (Replacing
>    most of the is_ methods from the 3rd version.)

Please, no, using subclasses when there is no behavioural change is
annoying. A "kind" attribute will handle this just fine.

>    I favor passing a class to Signature.format, because so many of
>    the formatting arguments would normally change in parallel.
>    But my tolerance for nested structures may be unusually high.

I'm actually inclined to drop a lot of that complexity altogether -
better to provide a simple default implementation, and if people want
anything else they can write their own.

>> 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.
>
> This means users must already be prepared to use hasattr with the
> Signature as well as the Parameters -- in which case, I don't see any
> harm in a few extra optional properties.

No, this gets the reasoning wrong. The optional properties are
optional solely because "None" and "not present" don't mean the same
thing - the attributes potentially being missing represents the fact
that annotations and default values may be omitted altogether.

> I would personally prefer to see the name (and qualname) and docstring,
> but it would make perfect sense to implement these by keeping a weakref
> to the original callable, and just delegating there unless/until the
> properties are explicitly changed.  I suspect others will have a use
> for additional delegated attributes, such as the self of boundmethods.

It is expected that higher level interfaces will often compose the
signature object with more information from the callable. That is
already well supported today, and is not the role of the signature
object. The signature object is being added purely to provide a
standard way to describe how a callable binds the supplied arguments
to the expected parameters, that's all.

> I do agree that __eq__ and __hash__ should depend at most on the
> parameters (including their order) and the annotation.
>
>> * 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``).
>
> For a specification, that feels a little too tied to the specific
> implementation.  How about:
>
>     Parameters will be ordered as they are in the function declaration.
>
> or even just:
>
>     Positional parameters will be ordered as they are in the function
>     declaration.
>
> because:
>    def f(*, a=4, b=5): pass
>
> and:
>    def f(*, b=5, a=4): pass
>
> should probably have equal signatures.
>
>
> Wild thought:  Instead of just *having* an OrderedDict of Parameters,
> should a Signature *be* that OrderedDict (with other attributes)?
> That is, should signature(testfn)["foo"] get the foo parameter?

No. While the sequence of parameters is obviously the most important
part of the signature, it's still much clearer to expose it as a
distinct attribute. If return annotations didn't exist, you may be
able to make a stronger case.

> I think it should state explicitly that by default, the return value
> will be a string that could be used to declare an equivalent function,
> if "Signature" were replaced with "def funcname".
>
> There are enough customization parameters that would often be changed
> together (e.g., to produce HTML output) that it might make sense to use
> overridable class defaults -- or even to make format a class itself.
>
> I also think it would make sense to delegate formatting the individual
> parameters to the parameter objects.  Yes, this does mean that the
> subclasses would be more than markers classes.

I'd like to see support for customising the formatted output dropped
from the PEP entirely. We can add that later after seeing how people
use the class, there's no need to try to guess in advance.

>> The structure of the Parameter object is:
>
>> * name : str
>>     The name of the parameter as a string.
>
> If there is no name, as with some builtins, will this be "", None or
> not set?

Positional parameters should still be given a meaningful name
(preferably matching the name used in their docstring and prose
documentation).

>
> (3rd edition)
>> * is_keyword_only : bool ...
>> * is_args : bool ...
>> * is_kwargs : bool ...
>
> (4th edition)
>> ... Parameter.POSITIONAL_ONLY ...
>> ... Parameter.POSITIONAL_OR_KEYWORD ...
>> ... Parameter.KEYWORD_ONLY ...
>> ... Parameter.VAR_POSITIONAL ...
>> ... Parameter.VAR_KEYWORD ...
>
> This set has already grown, and I can think of others I would like to
> use.  (Pseudo-parameters, such as a method's self instance, or an
> auxiliary variable.)

No. This is the full set of binding behaviours. "self" is just an
ordinary "POSITIONAL_OR_KEYWORD" argument (or POSITIONAL_ONLY, in some
builtin cases).

>
>    class BaseParameter: ...
>
>    # These two really are different
>    class ArgsParameter(BaseParameter): ...
>    class KwargsParameter(BaseParameter): ...
>
>    class KeywordParameter(BaseParameter): ...
>    class PositionalParameter(BaseParameter): ...
>    class Parameter(KeywordParameter, PositionalParameter): ...
>
> (I'm not sure that normal parameters should really be the bottom of an
> inheritance diamond, as opposed to a sibling.)

Completely unnecessary complexity. "kind" is not a free-form list,
it's the full set of available binding behaviours when mapping
arguments to parameters.

> Question:  These names are getting long.  Was there a reason not to use
> Sig and Param?

Yes, because the full names are much clearer, and there's no reason
people should be writing them out very often.

>> * implemented : bool
>
> This information is valuable, and should be at least an optional part
> of a signature (or a specific parameter, if there are no interactions).
> But I don't think a boolean is sufficient.

Users are free to subclass Signature (and Parameter) and add whatever
additional attributes and behaviour they like. inspect.signature(obj)
will faithfully copy whatever they place in __signature__.

>> Two parameters are equal when all their attributes are equal.
>
> I think that it would be better to specify which attributes matter,
> and let them be equal so long as those attributes matched.  I'll try
> to post details on the ticket, but roughly only the attributes
> specifically mentioned in this PEP should matter.

Agreed, since it should be made clear that subclasses will need to
override __eq__ if they want it to take additional attributes into
account.

> I'm not sure
> if positional parameters should also check position, or if that
> can be left to the Signature.

Positional parameters don't know their relative position, so it *has*
to be left to the signature.

Cheers,
Nick.

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


More information about the Python-Dev mailing list