mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 05:31:20 +00:00 
			
		
		
		
	allow keyword args after *args in a function call
This commit is contained in:
		
							parent
							
								
									de0de885f7
								
							
						
					
					
						commit
						2d735bc098
					
				
					 6 changed files with 30 additions and 13 deletions
				
			
		|  | @ -612,11 +612,11 @@ of arguments: | |||
|    call: `primary` "(" [`argument_list` [","] | ||||
|        : | `expression` `genexpr_for`] ")" | ||||
|    argument_list: `positional_arguments` ["," `keyword_arguments`] | ||||
|                 : ["," "*" `expression`] | ||||
|                 :   ["," "*" `expression`] ["," `keyword_arguments`] | ||||
|                 :   ["," "**" `expression`] | ||||
|                 : | `keyword_arguments` ["," "*" `expression`] | ||||
|                 : ["," "**" `expression`] | ||||
|                 : | "*" `expression` ["," "**" `expression`] | ||||
|                 :   ["," `keyword_arguments`] ["," "**" `expression`] | ||||
|                 : | "*" `expression` ["," `keyword_arguments`] ["," "**" `expression`] | ||||
|                 : | "**" `expression` | ||||
|    positional_arguments: `expression` ("," `expression`)* | ||||
|    keyword_arguments: `keyword_item` ("," `keyword_item`)* | ||||
|  | @ -674,12 +674,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): | ||||
|  |  | |||
|  | @ -113,7 +113,9 @@ dictorsetmaker: ( (test ':' test (comp_for | (',' test ':' test)* [','])) | | |||
| 
 | ||||
| classdef: 'class' NAME ['(' [arglist] ')'] ':' suite | ||||
| 
 | ||||
| arglist: (argument ',')* (argument [',']| '*' test [',' '**' test] | '**' test) | ||||
| arglist: (argument ',')* (argument [','] | ||||
|                          |'*' test (',' argument)* [',' '**' test]  | ||||
|                          |'**' test) | ||||
| argument: test [comp_for] | test '=' test  # Really [keyword '='] test | ||||
| 
 | ||||
| comp_iter: comp_for | comp_if | ||||
|  |  | |||
|  | @ -284,6 +284,14 @@ def pos2key2dict(p1, p2, *, k1=100, k2, **kwarg): return p1,p2,k1,k2,kwarg | |||
|         pos2key2dict(1,2,k2=100,tokwarg1=100,tokwarg2=200) | ||||
|         pos2key2dict(1,2,tokwarg1=100,tokwarg2=200, k2=100) | ||||
| 
 | ||||
|         # 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)") | ||||
| 
 | ||||
|         # argument annotation tests | ||||
|         def f(x) -> list: pass | ||||
|         self.assertEquals(f.__annotations__, {'return': list}) | ||||
|  |  | |||
|  | @ -75,7 +75,7 @@ def testSyntaxForManyArguments(self): | |||
| 
 | ||||
|     def testSyntaxErrorForFunctionCall(self): | ||||
|         self.assertRaisesSyntaxError("f(p, k=1, p2)") | ||||
|         self.assertRaisesSyntaxError("f(p, *(1,2), k1=100)") | ||||
|         self.assertRaisesSyntaxError("f(p, k1=50, *(1,2), k1=100)") | ||||
| 
 | ||||
|     def testRaiseErrorFuncallWithUnexpectedKeywordArgument(self): | ||||
|         self.assertRaises(TypeError, keywordonly_sum, ()) | ||||
|  |  | |||
|  | @ -1961,6 +1961,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; | ||||
|  |  | |||
|  | @ -1598,7 +1598,8 @@ static arc arcs_73_5[2] = { | |||
| static arc arcs_73_6[1] = { | ||||
| 	{0, 6}, | ||||
| }; | ||||
| static arc arcs_73_7[1] = { | ||||
| static arc arcs_73_7[2] = { | ||||
| 	{161, 5}, | ||||
| 	{32, 3}, | ||||
| }; | ||||
| static state states_73[8] = { | ||||
|  | @ -1609,7 +1610,7 @@ static state states_73[8] = { | |||
| 	{4, arcs_73_4}, | ||||
| 	{2, arcs_73_5}, | ||||
| 	{1, arcs_73_6}, | ||||
| 	{1, arcs_73_7}, | ||||
| 	{2, arcs_73_7}, | ||||
| }; | ||||
| static arc arcs_74_0[1] = { | ||||
| 	{24, 1}, | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Benjamin Peterson
						Benjamin Peterson