It's a Python compiler limitation to reduce the need for under-the-hood dictionary lookups. There's not actually an ambiguous case or anything they're avoiding.
You can see where the dict lookup would need to happen though:
def test(x, y): return x + y test(y=10, 5)
Follow the compiler from top-left to bottom-right...
With kwargs allowed to come before positional args:
- Read
y=10 - Put into
kwargs dict (expensive). - Read
5. - Check if first positional arg name
x is in kwargs dict (expensive). - Put into
x positional arg.
Without wkargs allowed before positional args:
- Read
y=10 - Put into
kwargs dict (expensive). - Read
5. - Throw and error (easy?)
Now consider the case where plain arguments are used, which (can be) fast.
def test(x, y): return x + y test(10, 5)
Keywords first allowed:
- Read
10. - Check
kwarg dict for x (expensive). - Put in
x arg. - Read
5. - Check
kwarg dict for y (expensive). - Put in
y arg.
Args must be first:
- Read
10. - Put in
x arg. - Read
5. - Put in
y arg.
This difference isn't compiled out in Python, because the byte-code still allows for dynamic function calls. Python devs decided to forbid keyword-first syntax to make the language a little faster at run time.
PS: There is also an argument that putting keywords before positional args is harder to read, but I'll leave aesthetic judgements to the critics. I think it looks fine.