Since yet another sentinel singleton sounds like a dead end, I suggest
to use [arg=value] syntax and require a default value in the
prototype, as currently required for *optional keyword* arguments.

"[...]" syntax for optional parameter is commonly used in Python
documentation (but the exact syntax for multiple optional arguments is
different than what I propose, see below). I already saw this syntax
for optional parameters in C and PHP languages at least.

Python prototype of the standard library and their generated signature:

    def bool([x=False])
    => bool([x])

    def bytearray([source=None], [encoding=None], errors="strict")
    => bytearray([source], [encoding], [errors])

    # in practice, default value of 'default' parameter (and maybe also 'key'?)
    # will more likely be a custom sentinel
    def sum(iterable, *args, [key=None], [default=None])
    => sum(iterable, *args, [key], [default])

    # "/" is an hypothetical marker for positional-only arguments
    def str.replace(old, new, [count=-1], /)
    => str.replace(old, new, [count], /)

    def pickle.dump(obj, file, [protocol=3], *, fix_imports=True)
    => pickle.dump(obj, file, [protocol], *, fix_imports=True)

An alternative for generated signature of multiple optional arguments
is "bytearray([source[, encoding[, errors]]])", but I'm not a big fan
of nested [...], IMHO it's harder to read. And I like the idea of
having a signature closer to the actual Python code.


Invalid syntaxes raising SyntaxError:

* no default value: "def func([x]): ..."
* optional arguments before *args: "def func(arg, [opt=None], *args):"

In practice, calling a function without an optional argument or pass
the (private?) sentinel as the optional argument should have the same
behaviour. Each module is free to decide how the sentinel is exposed
or not. For example, the inspect module has 2 sentinels: _empty is
exposed as Signature.empty and Parameter.empty, whereas _void is
private.

If I understood correctly, Argument Clinic already supports optional
positional arguments, and so doesn't need to be changed.


I'm not sure that it's useful for optional keyword-only arguments:

def func(*, [arg=None])
=> func(*, [arg])

The only difference with optional keyword-only arguments with a
default value is the signature:

def func(*, arg=None)
=> func(*, arg=None)

See also the discussion on converting the bisect functions to Argument
Clinic and issues with the generated signature:
http://bugs.python.org/issue28754

Victor
_______________________________________________
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to