Python 生成器作为函数参数
有人能解释为什么将生成器作为唯一的位置参数传递给函数似乎有特殊的规则吗 如果我们有:Python 生成器作为函数参数,python,python-3.x,syntax,python-2.x,generator-expression,Python,Python 3.x,Syntax,Python 2.x,Generator Expression,有人能解释为什么将生成器作为唯一的位置参数传递给函数似乎有特殊的规则吗 如果我们有: def f(*args): print "Success!" print args 正如预期的那样,这是可行的 >>> f(1, *[2]) Success! (1, 2) >>> f(*[2], 1) File "<stdin>", line 1 SyntaxError: only named ar
def f(*args):
print "Success!"
print args
>>> f(1, *[2])
Success!
(1, 2)
>>> f(*[2], 1)
File "<stdin>", line 1
SyntaxError: only named arguments may follow *expression
>>> f(1, *[2])
Success!
(1, 2)
>>> f(*[2], 1)
File "<stdin>", line 1
SyntaxError: only named arguments may follow *expression
>>f(*[2],1)
文件“”,第1行
SyntaxError:只有命名参数可以跟在*表达式后面
>>> f(1 for x in [1], *[2])
Success!
(generator object <genexpr> at 0x7effe06bdcd0>, 2)
>>f(1代表[1]、*[2]中的x)
成功!
(0x7Eff06BDCD0>处的生成器对象,2)
>>f(*[2],1代表[1]中的x)
成功!
(0x7Eff06BDCD0>处的生成器对象,2)
*args
和/或**kwargs
,则该表达式被接受为函数的参数。而Python2.6+允许这两种情况。Python 2.5只允许第3种情况但他们两人都反对:
i、 e.文档说明函数调用由主
(计算结果为可调用的表达式)组成,在括号中,后跟参数列表或仅是一个未附加参数的生成器表达式;
在参数列表中,所有生成器表达式都必须放在括号中
这个bug(尽管似乎还不知道)已经在Python 3.5的预发行版中修复。在Python 3.5中,生成器表达式周围始终需要括号,除非它是函数的唯一参数:
Python 3.5.0a4+ (default:a3f2b171b765, May 19 2015, 16:14:41)
[GCC 4.9.2] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> f(1 for i in [42], *a)
File "<stdin>", line 1
SyntaxError: Generator expression must be parenthesized if not sole argument
在此之前,这可能是一个语法错误。(阿莫里撰稿)
《忘记圆弧》;第3473期。)
然而,Python2.6并没有对关键字参数、位置参数或裸生成器表达式进行任何区分——对于解析器来说,它们都是
参数类型
根据Python规则,如果生成器表达式不是函数的唯一参数,则必须将其括起来。这在以下文件中得到验证:
但这同样适用于非非非独立生成器表达式的参数,如下所示:
因此,允许一个未加密的生成器表达式滑动通过
现在在Python3.5中,可以在函数调用的任何地方使用*args
,因此
为适应以下情况,更改了:
arglist: argument (',' argument)* [',']
及
和
及
如果在*args
或**kwargs
之前有一个未设定的生成器,则该生成器现在停止工作
为了找到这个bug,我尝试了各种Python版本。在2.5中,您将得到SyntaxError
:
Python 2.5.5 (r255:77872, Nov 28 2010, 16:43:48)
[GCC 4.4.5] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> f(*[1], 2 for x in [2])
File "<stdin>", line 1
f(*[1], 2 for x in [2])
这就是线索。在Python 3.5中,*splatting
是通用的;您可以在函数调用的任何位置使用它:
>>> print(*range(5), 42)
0 1 2 3 4 42
因此,Python 3.5中确实修复了实际的bug(生成器使用*star
,不带括号),并且可以在Python 3.4和3.5之间发生的变化中找到bug,这些变化不是完全重复的,而是非常相似的:。TL;DR似乎是一个实现细节——它就是这样工作的。注意:案例2应该在Python3.5+中工作(因为Python3.5已经过时),现在它告诉我们案例3(实际上也是案例4)已经修复。它在3.5中没有固定-只是在生成器周围放置parens,其行为是相同的。@viraptor很好,在3.4中,括号中的表达式给出了一个错误,嗯?在3.4.3上运行:f(*[1],1代表[1]中的x
=>(,1)
@viraptorf(*[1]),(1代表[1]中的x)是Python 3.4上的语法错误。它在Python3.5中是有效的。如果可以的话,我会给这个答案镀金,谢谢你提供了相关的C源代码!
else if (TYPE(CHILD(ch, 1)) == gen_for) {
e = ast_for_genexp(c, ch);
if (!e)
return NULL;
asdl_seq_SET(args, nargs++, e);
}
arglist: argument (',' argument)* [',']
argument: ( test [comp_for] |
test '=' test |
'**' test |
'*' test )
for (i = 0; i < NCH(n); i++) {
node *ch = CHILD(n, i);
if (TYPE(ch) == argument) {
if (NCH(ch) == 1)
nargs++;
else if (TYPE(CHILD(ch, 1)) == comp_for)
ngens++;
else if (TYPE(CHILD(ch, 0)) == STAR)
nargs++;
else
/* TYPE(CHILD(ch, 0)) == DOUBLESTAR or keyword argument */
nkeywords++;
}
}
func(i for i in [42], *args)
func(i for i in [42], **kwargs)
Python 2.5.5 (r255:77872, Nov 28 2010, 16:43:48)
[GCC 4.4.5] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> f(*[1], 2 for x in [2])
File "<stdin>", line 1
f(*[1], 2 for x in [2])
Python 3.5.0a4+ (default:a3f2b171b765, May 19 2015, 16:14:41)
[GCC 4.9.2] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> f(*[1], 2 for x in [2])
File "<stdin>", line 1
SyntaxError: Generator expression must be parenthesized if not sole argument
f(*[1], (2 for x in [2]))
>>> print(*range(5), 42)
0 1 2 3 4 42