[Python-Dev] PEP 362 Third Revision

Alexandre Zani alexandre.zani at gmail.com
Thu Jun 14 16:50:42 CEST 2012


On Thu, Jun 14, 2012 at 6:50 AM, Yury Selivanov <yselivanov.ml at gmail.com> wrote:
> On 2012-06-14, at 8:06 AM, Victor Stinner wrote:
>> Sorry if I'm asking dummy questions, I didn't follow the discussion.
>>
>>> * format(...) -> str
>>>    Formats the Signature object to a string.  Optional arguments allow
>>>    for custom render functions for parameter names,
>>>    annotations and default values, along with custom separators.
>>
>> Hum, what are these "custom render functions"? Can you give an example?
>
> That's how the function looks right now (I'm not sure we should load
> the PEP with this):
>
>    def format(self, *, format_name=str,
>                        format_default=repr,
>                        format_annotation=formatannotation,
>                        format_args=(lambda param: '*' + str(param)),
>                        format_kwargs=(lambda param: '**' + str(param)),
>
>                        token_params_separator=', ',
>                        token_kwonly_separator='*',
>                        token_left_paren='(',
>                        token_right_paren=')',
>                        token_colon=':',
>                        token_eq='=',
>                        token_return_annotation=' -> '):
>
>        '''Format signature to a string.
>
>        Arguments (all optional):
>
>        * format_name : A function to format names of parameters.  Parameter
>          won't be rendered if ``None`` is returned.
>        * format_default : A function to format default values of parameters.
>          Default value won't be rendered if ``None`` is returned.
>        * format_annotation : A function to format parameter annotations.
>          Annotation won't be rendered if ``None`` is returned.
>        * format_args : A function to render ``*args`` like parameters.
>          Parameter won't be rendered if ``None`` is returned.
>        * format_kwargs : A function to render ``**kwargs`` like parameters.
>          Parameter won't be rendered if ``None`` is returned.
>        * token_params_separator : A separator for parameters.  Set to
>          ', ' by default.
>        * token_kwonly_separator : A separator for arguments and
>          keyword-only arguments.  Defaults to '*'.
>        * token_left_paren : Left signature parenthesis, defaults to '('.
>        * token_right_paren : Left signature parenthesis, defaults to ')'.
>        * token_colon : Separates parameter from its annotation,
>          defaults to ':'.
>        * token_eq : Separates parameter from its default value, set to
>          '=' by default.
>        * token_return_annotation : Function return annotation, defaults
>          to ' -> '.
>        '''
>
> I've designed it in such a way, that everything is configurable, so you
> can render functions to color-term, HTML, or whatever else.
>
>>> * is_keyword_only : bool
>>>    True if the parameter is keyword-only, else False.
>>> * is_args : bool
>>>    True if the parameter accepts variable number of arguments
>>>    (``*args``-like), else False.
>>> * is_kwargs : bool
>>>    True if the parameter accepts variable number of keyword
>>>    arguments (``**kwargs``-like), else False.
>>
>> Hum, why not using a attribute with a string value instead of 3
>> attribute? For example:
>> * argtype: "index", "varargs", "keyword" or "keyword_only"
>>
>> It would avoid a possible inconsitency (ex: is_args=True and
>> is_kwargs=True). And it would help to implement something like a C
>> switch/case using a dict: argtype => function for functions using
>> signatures.
>
> Originally, I thought the the line:
>
>   if parameters.is_args
>
> is better looking that:
>
>   if parameters.kind == 'vararg'
>
> But, I like your arguments regarding inconsistency and dispatch
> through a dict (someone may find it useful).  Also, Larry gave
> another one - who knows if we add another type of arguments in
> the future.
>
> I guess if nobody really wants to keep 'is_args', we can alter the
> PEP.
>
> Let's consider replacement of 'Parameter.is_*' set of attributes with
> a single 'Parameter.kind' attribute, which will have the following
> possible values: 'positional', 'vararg', 'keyword-only', 'varkwarg'.
>
> (I think 'positional' is more intuitive than 'index'?)
>

I disagree largely for readability reasons. As the PEP stands, I can
look at a Parameter object and immediately understand what the
different possible values are by just listing its attributes. The kind
attribute makes that harder.

Comparing with strings is error prone. If I do param.is_varargs
(adding an s at the end of the attribute name) I will see an attribute
error and know what is going on. If I do the same mistake with the
kind attribute param.kind == "varargs", the expression will just
always be False without any explanation.

>>> * is_implemented : bool
>>>    True if the parameter is implemented for use.  Some platforms
>>>    implement functions but can't support specific parameters
>>>    (e.g. "mode" for ``os.mkdir``).  Passing in an unimplemented
>>>    parameter may result in the parameter being ignored,
>>>    or in NotImplementedError being raised.  It is intended that
>>>    all conditions where ``is_implemented`` may be False be
>>>    thoroughly documented.
>>
>> I suppose that the value depends on the running platform? (For
>> example, you may get a different value on Linux and Windows.)
>
> Correct.
>
>>> Implementation
>>> ==============
>>>
>>>    - If the object has a ``__signature__`` attribute and if it
>>>      is not ``None`` - return a deepcopy of it
>>
>> Oh, why copying the object? It may impact performances. If fhe caller
>> knows that it will modify the signature, it can deepcopy the
>> signature.
>
> There was a discussion on this topic earlier on python-dev.
> In short - as we usually create new signatures with each 'signature()'
> call, users will expect that they can modify those freely.  But if we
> have one defined in __signature__, without copying it, all its
> modifications will be persistent across 'signature()' calls.  So the
> deepcopy here is required more for the consistency reasons.  Besides,
> I don't think that 'signature()' will be used extensively in
> performance-critical types of code.  And even if it is - you can just
> cache it manually.
>
>>>        - If it is ``None`` and the object is an instance of
>>>          ``BuiltinFunction``, raise a ``ValueError``
>>
>> What about builtin functions (ex: len)? Do you plan to add a
>> __signature__ attribute? If yes, something created on demand or
>> created at startup?
>
> Larry is going to add signatures to some 'os' module functions. But
> that would it for 3.3, I guess.
>
>> It would be nice to have a C API to create Signature objects, maybe
>> from the same format string than PyArg_Parse*() functions. But it can
>> be implemented later.
>
> Then parameters will lack the 'name' attribute.  I think we need another
> approach here.
>
>> Is it possible to build a Signature object from a string describing
>> the prototype (ex: "def f(x, y): pass")? (I mean: do you plan to add
>> such function?)
>
>
> There are no plans to add it now (no good reasons to include such
> functionality in 3.3 at least)
>
> Thank you,
>
> -
> Yury
> _______________________________________________
> Python-Dev mailing list
> Python-Dev at python.org
> http://mail.python.org/mailman/listinfo/python-dev
> Unsubscribe: http://mail.python.org/mailman/options/python-dev/alexandre.zani%40gmail.com


More information about the Python-Dev mailing list