allow keyword args to be passed in after *args #3473
This commit is contained in:
parent
d9ccf8c547
commit
80f0ed5bb1
|
@ -625,11 +625,11 @@ of arguments:
|
|||
call: `primary` "(" [`argument_list` [","]
|
||||
: | `expression` `genexpr_for`] ")"
|
||||
argument_list: `positional_arguments` ["," `keyword_arguments`]
|
||||
: ["," "*" `expression`]
|
||||
: ["," "**" `expression`]
|
||||
: ["," "*" `expression`] ["," `keyword_arguments`]
|
||||
: ["," "**" `expression`]
|
||||
: | `keyword_arguments` ["," "*" `expression`]
|
||||
: ["," "**" `expression`]
|
||||
: | "*" `expression` ["," "**" `expression`]
|
||||
: ["," "**" `expression`]
|
||||
: | "*" `expression` ["," "*" `expression`] ["," "**" `expression`]
|
||||
: | "**" `expression`
|
||||
positional_arguments: `expression` ("," `expression`)*
|
||||
keyword_arguments: `keyword_item` ("," `keyword_item`)*
|
||||
|
@ -686,12 +686,13 @@ there were no excess keyword arguments.
|
|||
|
||||
If the syntax ``*expression`` appears in the function call, ``expression`` must
|
||||
evaluate to a sequence. Elements from this sequence are treated as if they were
|
||||
additional positional arguments; if there are positional arguments *x1*,...,*xN*
|
||||
, and ``expression`` evaluates to a sequence *y1*,...,*yM*, this is equivalent
|
||||
to a call with M+N positional arguments *x1*,...,*xN*,*y1*,...,*yM*.
|
||||
additional positional arguments; if there are positional arguments *x1*,...,
|
||||
*xN*, and ``expression`` evaluates to a sequence *y1*, ..., *yM*, this is
|
||||
equivalent to a call with M+N positional arguments *x1*, ..., *xN*, *y1*, ...,
|
||||
*yM*.
|
||||
|
||||
A consequence of this is that although the ``*expression`` syntax appears
|
||||
*after* any keyword arguments, it is processed *before* the keyword arguments
|
||||
A consequence of this is that although the ``*expression`` syntax may appear
|
||||
*after* some keyword arguments, it is processed *before* the keyword arguments
|
||||
(and the ``**expression`` argument, if any -- see below). So::
|
||||
|
||||
>>> def f(a, b):
|
||||
|
|
|
@ -130,7 +130,9 @@ dictmaker: test ':' test (',' test ':' test)* [',']
|
|||
|
||||
classdef: 'class' NAME ['(' [testlist] ')'] ':' suite
|
||||
|
||||
arglist: (argument ',')* (argument [',']| '*' test [',' '**' test] | '**' test)
|
||||
arglist: (argument ',')* (argument [',']
|
||||
|'*' test (',' argument)* [',' '**' test]
|
||||
|'**' test)
|
||||
argument: test [gen_for] | test '=' test # Really [keyword '='] test
|
||||
|
||||
list_iter: list_for | list_if
|
||||
|
|
|
@ -282,6 +282,14 @@ class GrammarTests(unittest.TestCase):
|
|||
def d32v((x,)): pass
|
||||
d32v((1,))
|
||||
|
||||
# keyword arguments after *arglist
|
||||
def f(*args, **kwargs):
|
||||
return args, kwargs
|
||||
self.assertEquals(f(1, x=2, *[3, 4], y=5), ((1, 3, 4),
|
||||
{'x':2, 'y':5}))
|
||||
self.assertRaises(SyntaxError, eval, "f(1, *(2,3), 4)")
|
||||
self.assertRaises(SyntaxError, eval, "f(1, x=2, *(3,4), x=5)")
|
||||
|
||||
# Check ast errors in *args and *kwargs
|
||||
check_syntax_error(self, "f(*g(1=2))")
|
||||
check_syntax_error(self, "f(**g(1=2))")
|
||||
|
|
|
@ -1898,6 +1898,11 @@ ast_for_call(struct compiling *c, const node *n, expr_ty func)
|
|||
"non-keyword arg after keyword arg");
|
||||
return NULL;
|
||||
}
|
||||
if (vararg) {
|
||||
ast_error(CHILD(ch, 0),
|
||||
"only named arguments may follow *expression");
|
||||
return NULL;
|
||||
}
|
||||
e = ast_for_expr(c, CHILD(ch, 0));
|
||||
if (!e)
|
||||
return NULL;
|
||||
|
|
|
@ -1609,7 +1609,8 @@ static arc arcs_74_5[2] = {
|
|||
static arc arcs_74_6[1] = {
|
||||
{0, 6},
|
||||
};
|
||||
static arc arcs_74_7[1] = {
|
||||
static arc arcs_74_7[2] = {
|
||||
{162, 5},
|
||||
{31, 3},
|
||||
};
|
||||
static state states_74[8] = {
|
||||
|
@ -1620,7 +1621,7 @@ static state states_74[8] = {
|
|||
{4, arcs_74_4},
|
||||
{2, arcs_74_5},
|
||||
{1, arcs_74_6},
|
||||
{1, arcs_74_7},
|
||||
{2, arcs_74_7},
|
||||
};
|
||||
static arc arcs_75_0[1] = {
|
||||
{28, 1},
|
||||
|
|
Loading…
Reference in New Issue