In the midst of work on the issue #17481, it became apparent that we need a way of specifying optional/grouped parameters.
One good example of grouped parameters in python is the `type` function. Basically, it has two different signatures: * type(name, bases, dict) * type(object) Which we can combine in one, if we define a notion of grouped parameters: * type(object_or_name, [bases, dict]) Another good example, is 'itertools.repeat'. Its signature is "(elem[, n])". If "n" argument is passed, then it's how many times the "elem" will be repeated, and if it is not passed at all, then "elem" will be repeated endlessly. One way of emulating this behavior in pure python is to define a special private marker object and use it as a default value: _optional = object() def repeat(elem, n=_optional): if n is _optional: # `n` wasn't passed, repeat indefinitely else: # we have something for `n` One of the problems with the above approach is how to represent its signature, how to document it clearly. Another one, is that there is no common marker, so whenever this is needed, a new marker is invented. Now, the more I think about having a concept of grouped parameters, the more different things to consider and take care of appear: * In issue #17481 Larry proposed that parameters will have a group id (arbitrary), and perhaps parent group id, to make it possible to have nested groups. * API for retrieving grouped parameters for the Signature objects. Something akin to what we have for ``regex.Match`` objects, probably. * An accepted and documented method of declaring groups for pure python function would be a nice thing to have. * Will we have groups for keyword-only parameters? Can we combine ``*args`` and a keyword-only parameter in a group? etc. That seems to be a lot of work (some of it is maybe enough for a PEP.) So before committing to the parameters groups idea, I'd like to propose somewhat simpler, but powerful enough to solve our todays problems solution. What if we add a notion of "optional" parameters? * ``Parameter.__init__ `` will receive one more keyword-only argument: ``optional``, ``False`` by default. * We add a special marker ``Parameter.optional`` (or some other name, like ``inspect.optional`` or ``functools.optional``), and teach ``inspect.signature`` to recognize it. So for pure-python functions, if you want to define an optional parameter, you would write: ``def mytype(name_or_obj, bases=Parameter.optional, dict=Parameter.optional)`` * Argument Clinic may get a new syntax for specifying if parameter is optional. * We standardize how optional parameters should look like in documentation and ``Signature.__str__``. In PEP 362 we used <optional> notation for optional parameters: ``foo(param=<optional>)``, but we also can use square brackets for that: ``bar([spam][, ham])``. With this approach, a signature of the ``type`` function would look like: ``type(object_or_name[, bases][, dict])``. The main downside is that it's not immediately apparent, that you can only pass either one argument "(object)", or all three arguments "(name, bases, dict)". But that's something, that a good documentation (and meaningful exceptions) could help with. The advantages if this approach, is that it works for all types of parameters, and that the implementation is going to be simpler than groups (and we will need fewer new APIs). Yury _______________________________________________ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com