On 09. 11. 21 10:50, Chris Angelico wrote:
A more extreme case is functions with an optional *group*. In curses, the first two arguments to addch are optional. In `help()` it's documented as `window.addch([y, x,] ch[, attr=...])` and you can call it as one of:On Tue, Nov 9, 2021 at 8:38 PM Sebastian Rittau <[email protected]> wrote:Currently, Python doesn't allow non-default arguments after default arguments: >>> def foo(x=None, y): pass File "<stdin>", line 1 def foo(x=None, y): pass ^ SyntaxError: non-default argument follows default argument I believe that at the time this was introduced, no use cases for this were known and this is is supposed to prevent a source of bugs. I have two use cases for this, one fringe, but valid, the other more important: The fringe use case: Suppose you have a function that takes a 2D coordinate value as separate "x" and "y" arguments. The "x" argument is optional, the "y" argument isn't. Currently there are two ways to do this, none of them particularly great: def foo(y, x): # reverse x and y arguments, confusing ... def foo(x, y=None): # Treat the x argument as y if only one argument is provided if y is None: x, y = y, x ... To me, the "natural" solution looks like this: def foo(x=None, y): ... # Called like this: foo(1, 2) foo(y=2) This could also be useful when evolving APIs. For example there is a function "bar" that takes two required arguments. In a later version, the first argument gains a useful default, the second doesn't. There is no sensible way to evolve the API at the moment.What would this mean, though: foo(2) Is that legal? If it is, it has to be the same as foo(y=2), by your definition. But that would mean that it's hard to get your head around the mapping of arguments and parameters. foo(1, 2) # x=1, y=2 foo(1) # x=None, y=1 There are a very very few functions in Python that have this sort of odd behaviour (range() being probably the only one most programmers will ever come across), and it's not something to encourage.
window.addch(ch) window.addch(ch, attr) window.addch(y, x, ch) window.addch(y, x, ch, attr) see: https://docs.python.org/3/library/curses.html#curses.window.addchSupporting this was a headache for Argument Clinic (PEP 436), and AFAIK it still isn't possible to express this as an inspect.Signature (PEP 362). Allowing non-default arguments after default arguments would mean introspection tools (and code that uses them) would need to be changed to prepare for the new possibilities. It's not free. And for the "encoding" case: IMO, varying the return type based on an optional "encoding" argument" is a holdover from the pre-typing era, when return types were only specified in the documentation -- just like "addch" is a holdover from the days when function signatures were only described in the docs. Nowadays, I'd consider it bad API design. The @overloads are ugly but they work -- just like the API itself. IMO we shouldn't add special cases to encourage more of it.
+1. I'm not sure if it's possible to mark args as keyword-only in the type stubs while keeping actual implementation backwards-compatible, but if it is, it might be a good option.I would instead recommend making the parameters keyword-only, which would allow any of them to have defaults or not have defaults. In terms of useful API design, this is usually more helpful than having an early parameter omitted.
_______________________________________________ Python-Dev mailing list -- [email protected] To unsubscribe send an email to [email protected] https://mail.python.org/mailman3/lists/python-dev.python.org/ Message archived at https://mail.python.org/archives/list/[email protected]/message/JIK7EJLN4WG4EJE4UVYVLUORGQB6XQWR/ Code of Conduct: http://python.org/psf/codeofconduct/