Why must required parameters be placed before default parameters in a function defintion?

From the language reference:

If a parameter has a default value, all following parameters up until the “* ” must also have a default value — this is a syntactic restriction that is not expressed by the grammar.

I would like to understand why this rule is in place.

Most answers I have come across (e.g. this one on Stack Overflow) suggest that the rule is needed to prevent ambiguity during the argument matching process. So for example,. if definitions such as def f(a=True, b=False, x, y): pass were permitted, then calls such as f(1, 2) would be “ambiguous” because the interpreter wouldn’t know whether to match 1 and 2 to a and b or to x and y.

But I am not sure if this is the real reason. My understanding of the matching process is that positional arguments, such as 1 and 2 in the example above, are matched to parameters from left to right. So if def f(a=True, b=False, x, y): pass were valid syntax, then the interpreter would simply match 1 and 2 to the parameters a and b, respectively, and then throw a TypeError because it received fewer arguments than required by the function. There doesn’t seem to be any ambiguity here.

The only problem I could make out with syntax like def f(a=True, b=False, x, y): pass is that it makes it harder for the caller to convey to the interpreter that they wish to use a default value. For example, if we wished to override the default for a but use the default for b, we would have to use a call syntax like f(False, , 1, 2). This is not very readable and sort of defeats the purpose of having a default value, so the only other option is to prohibit default parameters from preceding required parameters in the function definition itself. Could this be why the rule is in place?

If you suppose that there is no ambiguity, then you also suppose that there is no use.

By your rules, as you’ve already analyzed, you can’t call the function with two arguments - similarly, you can’t call it with any fewer than four - since otherwise there will no way for y to receive a value. And if you supply four arguments, then you are explicitly specifying all the values. In no case do the defaults get used.

Unless, of course…

“Harder” is an understatement. We don’t have that syntax; it would have to be implemented specially, and then it would be inconsistent with how commas work everywhere else in the language. And then there’s the inconsistency that if I want to fill in the first two values of four, I only have to write (x,y) (and not (x,y,,), but to fill in the last two I need extra commas (,,x,y).

It’s also kinda, well, missing the point: positional arguments are ones where you’re supposed to be able to tell what’s what, according to the order of the values. So why should we then also just allow for skipping spots?

1 Like

Thank you for getting back so quickly @kknechtel.

Could you please clarify what you mean here:

If you suppose that there is no ambiguity, then you also suppose that there is no use.