[Python-Dev] Order of positional and keyword arguments

Serhiy Storchaka storchaka at gmail.com
Thu Apr 26 15:25:09 EDT 2018

There is an inconsistence in passing arguments to functions.

Explicit positional arguments should precede keyword arguments (both 
explicit and variable), but variable positional arguments can follow 
explicit keyword arguments and precede variable keyword arguments.

For example, for function

     def f(a=None, b=None):
         return a, b

the following is valid syntax:

     f(1, b=2)
     f(1, **{'b': 2})
     f(*[1], b=2)
     f(*[1], **{'b': 2})
     f(b=2, *[1])

but the following is an error:

     f(b=2, 1)
     f(**{'b': 2}, 1)
     f(**{'b': 2}, *[1])

f(b=2, *[1]) is surprised in two ways:

1. Argument values are passed not in order. The first value is assigned 
to the second parameter, and the second value is assigned to the first 

2. Argument values are evaluated not from left to right. This 
contradicts the general rule that expressions are evaluated from left to 
right (with few known exceptions).

I never seen the form `f(b=2, *[1])` in practice (though the language 
reference contains an explicit example for it), and it looks weird to 
me. I don't see reasons of writing `f(b=2, *[1])` instead of more 
natural `f(*[1], b=2)`. I propose to disallow it.

This will also make the grammar simpler. Current grammar:

    argument_list: `positional_arguments` ["," `starred_and_keywords`]
                 :   ["," `keywords_arguments`]
                 : | `starred_and_keywords` ["," `keywords_arguments`]
                 : | `keywords_arguments`
    positional_arguments: ["*"] `expression` ("," ["*"] `expression`)*
    starred_and_keywords: ("*" `expression` | `keyword_item`)
                 : ("," "*" `expression` | "," `keyword_item`)*
    keywords_arguments: (`keyword_item` | "**" `expression`)
                 : ("," `keyword_item` | "," "**" `expression`)*
    keyword_item: `identifier` "=" `expression`

Proposed grammar:

    argument_list: `positional_arguments` ["," `keywords_arguments`]
                 : | `keywords_arguments`
    positional_arguments: ["*"] `expression` ("," ["*"] `expression`)*
    keywords_arguments: `keyword_argument` ("," `keyword_argument`)*
    keyword_argument: `identifier` "=" `expression` | "**" `expression`

More information about the Python-Dev mailing list