gpt4 book ai didi

python - 生成器作为函数参数

转载 作者:行者123 更新时间:2023-12-03 08:11:06 32 4
gpt4 key购买 nike

谁能解释为什么将生成器作为唯一的位置参数传递给函数似乎有特殊的规则?
如果我们有:

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 for x in [1], *[2])
    Success!
    (generator object <genexpr> at 0x7effe06bdcd0>, 2)
  • 这行得通,但是我不明白为什么。它不应该以与2相同的方式失败吗?
    >>> f(*[2], 1 for x in [1])
    Success!
    (generator object <genexpr> at 0x7effe06bdcd0>, 2)
  • 最佳答案

    3.和4.在所有Python版本上都应该是语法错误。 但是,您发现了一个影响Python 2.5-3.4的错误,该错误随后是posted to the Python issue tracker。由于该错误,如果未带括号的生成器表达式仅伴随*args和/或**kwargs,则该表达式被接受为函数的参数。尽管Python 2.6+允许情况3和4.都使用,但Python 2.5仅允许情况3和-但这两个都反对documented grammar:

    call    ::=     primary "(" [argument_list [","]
    | expression genexpr_for] ")"

    也就是说,文档说函数调用由 primary(计算结果为可调用的表达式)组成,后跟括号中的参数列表或仅是未括号的生成器表达式;
    在参数列表中,所有生成器表达式都必须放在括号中。

    此错误(尽管似乎未知)已在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

    现在,这已记录在 What's New in Python 3.5中,这要感谢DeTeReR发现了此错误。

    错误分析

    对Python 2.6进行了更改,即 allowed the use of keyword arguments after *args :

    It’s also become legal to provide keyword arguments after a *args argument to a function call.

    >>> def f(*args, **kw):
    ... print args, kw
    ...
    >>> f(1,2,3, *(4,5,6), keyword=13)
    (1, 2, 3, 4, 5, 6) {'keyword': 13}

    Previously this would have been a syntax error. (Contributed by Amaury Forgeot d’Arc; issue 3473.)



    但是,Python 2.6 grammar在关键字参数,位置参数或裸生成器表达式之间没有任何区别-它们都是解析器的 argument类型。

    根据Python规则,如果生成器表达式不是函数的唯一参数,则必须将其括起来。这在 Python/ast.c 中得到了验证:
    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)) == gen_for)
    ngens++;
    else
    nkeywords++;
    }
    }
    if (ngens > 1 || (ngens && (nargs || nkeywords))) {
    ast_error(n, "Generator expression must be parenthesized "
    "if not sole argument");
    return NULL;
    }

    但是,此函数完全不考虑 *args,它仅查找普通的位置参数和关键字参数。

    在同一函数的更下方,有一个针对 non-keyword arg after keyword arg生成的错误消息:
    if (TYPE(ch) == argument) {
    expr_ty e;
    if (NCH(ch) == 1) {
    if (nkeywords) {
    ast_error(CHILD(ch, 0),
    "non-keyword arg after keyword arg");
    return NULL;
    }
    ...

    但这再次适用于不是非括号生成器表达式的参数 evidenced by the else if statement:
    else if (TYPE(CHILD(ch, 1)) == gen_for) {
    e = ast_for_genexp(c, ch);
    if (!e)
    return NULL;
    asdl_seq_SET(args, nargs++, e);
    }

    因此,允许使用非括号的生成器表达式滑移传递。

    现在在Python 3.5中,可以在函数调用中的任何位置使用 *args,因此
    Grammar已更改为适应以下情况:
    arglist: argument (',' argument)*  [',']


    argument: ( test [comp_for] |
    test '=' test |
    '**' test |
    '*' test )

    for loop was changed
    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)

    现在在无括号生成器 *args**kwargs之前的位置现在停止工作。

    为了找到该错误,我尝试了各种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的预发布版本之前已得到修复:
    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

    但是,带括号的生成器表达式可以在Python 3.5中使用,但不能在Python 3.4中使用:
    f(*[1], (2 for x in [2]))

    这就是线索。在Python 3.5中, *splatting是通用的;您可以在函数调用中的任何位置使用它:
    >>> print(*range(5), 42)
    0 1 2 3 4 42

    因此,实际的错误(生成器在不带括号的情况下使用 *star生成)确实已在Python 3.5中修复,并且该错误可以在Python 3.4和3.5之间进行了更改。

    关于python - 生成器作为函数参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42262726/

    32 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com