summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBenjamin Peterson <benjamin@python.org>2008-08-19 19:52:46 (GMT)
committerBenjamin Peterson <benjamin@python.org>2008-08-19 19:52:46 (GMT)
commit80f0ed5bb1b38a615d92bdf2b3b3dad854dd06d9 (patch)
tree3c75d17c436a3d9f6b8c9f8fa58b4ec6fa2badbe
parentd9ccf8c547f3163946462fd382991b27d4d1a4ee (diff)
downloadcpython-80f0ed5bb1b38a615d92bdf2b3b3dad854dd06d9.zip
cpython-80f0ed5bb1b38a615d92bdf2b3b3dad854dd06d9.tar.gz
cpython-80f0ed5bb1b38a615d92bdf2b3b3dad854dd06d9.tar.bz2
allow keyword args to be passed in after *args #3473
-rw-r--r--Doc/reference/expressions.rst19
-rw-r--r--Grammar/Grammar4
-rw-r--r--Lib/test/test_grammar.py8
-rw-r--r--Python/ast.c5
-rw-r--r--Python/graminit.c5
5 files changed, 29 insertions, 12 deletions
diff --git a/Doc/reference/expressions.rst b/Doc/reference/expressions.rst
index 867074a..1566a99 100644
--- a/Doc/reference/expressions.rst
+++ b/Doc/reference/expressions.rst
@@ -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):
diff --git a/Grammar/Grammar b/Grammar/Grammar
index b014c72..865d44c 100644
--- a/Grammar/Grammar
+++ b/Grammar/Grammar
@@ -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
diff --git a/Lib/test/test_grammar.py b/Lib/test/test_grammar.py
index e749e44..f8cef6a 100644
--- a/Lib/test/test_grammar.py
+++ b/Lib/test/test_grammar.py
@@ -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))")
diff --git a/Python/ast.c b/Python/ast.c
index b6a5e0f..8414c74 100644
--- a/Python/ast.c
+++ b/Python/ast.c
@@ -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;
diff --git a/Python/graminit.c b/Python/graminit.c
index 14a41d1..e65a992 100644
--- a/Python/graminit.c
+++ b/Python/graminit.c
@@ -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},