【问题标题】:Python: print a generator expression?Python:打印生成器表达式?
【发布时间】:2021-04-26 07:00:29
【问题描述】:

在 Python shell 中,如果我输入一个列表理解,例如:

>>> [x for x in string.letters if x in [y for y in "BigMan on campus"]]

我得到了一个很好的打印结果:

['a', 'c', 'g', 'i', 'm', 'n', 'o', 'p', 's', 'u', 'B', 'M']

字典理解也一样:

>>> {x:x*2 for x in range(1,10)}
{1: 2, 2: 4, 3: 6, 4: 8, 5: 10, 6: 12, 7: 14, 8: 16, 9: 18}

如果我输入一个生成器表达式,我会得到不那么友好的响应:

>>> (x for x in string.letters if x in (y for y in "BigMan on campus"))
<generator object <genexpr> at 0x1004a0be0>

我知道我能做到:

>>> for i in _: print i,
a c g i m n o p s u B M

除此之外(或编写辅助函数),我能否在交互式 shell 中轻松评估和打印该生成器对象?

【问题讨论】:

  • 这里真正的问题是什么?你错过了什么?
  • @pynator:“真正的问题”是我希望能够打印generator object 的内容,因为我在交互式提示下交互式地构建了一个理解。调用 list(_) 就可以做到这一点。我所做的是使用列表推导然后将它们转换为更大代码中的 genexp。这些在运行时可能会以列表推导不会失败的方式失败。
  • 简短的回答是生成器表达式无法打印,因为它的值不存在;它们是按需生成的。您可以做的(假设生成器在某个时候停止)是从中获取所有值,例如使用list(),然后打印它们。
  • 另一种方法是x = (i for i in range(1)); print(*x)

标签: python iterator generator


【解决方案1】:

您可以将表达式包装在对list 的调用中:

>>> list(x for x in string.letters if x in (y for y in "BigMan on campus"))
['a', 'c', 'g', 'i', 'm', 'n', 'o', 'p', 's', 'u', 'B', 'M']

【讨论】:

    【解决方案2】:

    与列表或字典不同,生成器可以是无限的。这样做是行不通的:

    def gen():
        x = 0
        while True:
            yield x
            x += 1
    g1 = gen()
    list(g1)   # never ends
    

    另外,读取生成器会改变它,因此没有一种完美的方式来查看它。 要查看生成器输出的示例,您可以这样做

    g1 = gen()
    [g1.next() for i in range(10)]
    

    【讨论】:

    • 投了赞成票,因为生成器可以是无限的,因此会导致循环或完全停止(取决于您的规格(大声笑))。
    • 在 Python 3 中使用 [next(g1) for i in range(10)]
    【解决方案3】:

    或者您总是可以通过迭代器map,而无需构建中间列表:

    >>> _ = map(sys.stdout.write, (x for x in string.letters if x in (y for y in "BigMan on campus")))
    acgimnopsuBM
    

    【讨论】:

    • 这是唯一实际打印生成器内容而不创建巨大对象的答案。
    【解决方案4】:

    快速回答:

    在生成器表达式周围使用list()(几乎)完全等同于在其周围使用[] 括号。所以是的,你可以这样做

    >>> list((x for x in string.letters if x in (y for y in "BigMan on campus")))
    

    但你也可以这样做

    >>> [x for x in string.letters if x in (y for y in "BigMan on campus")]
    

    是的,这会将生成器表达式转换为列表推导式。这是同一件事,并在其上调用 list() 。 所以将生成器表达式变成列表的方法是在它周围加上括号。

    详细解释:

    生成器表达式是“裸”for 表达式。像这样:

    x*x for x in range(10)
    

    现在,你不能把它单独放在一行上,你会得到一个语法错误。但是你可以在它周围加上括号。

    >>> (x*x for x in range(10))
    <generator object <genexpr> at 0xb7485464>
    

    这有时被称为生成器推导,虽然我认为正式名称仍然是生成器表达式,但实际上并没有任何区别,括号只是为了使语法有效。如果您将其作为唯一参数传递给函数,则不需要它们,例如:

    >>> sorted(x*x for x in range(10))
    [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
    

    基本上,Python 3 和 Python 2.7 中可用的所有其他推导式只是生成器表达式周围的语法糖。集合理解:

    >>> {x*x for x in range(10)}
    {0, 1, 4, 81, 64, 9, 16, 49, 25, 36}
    
    >>> set(x*x for x in range(10))
    {0, 1, 4, 81, 64, 9, 16, 49, 25, 36}
    

    字典理解:

    >>> dict((x, x*x) for x in range(10))
    {0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81}
    
    >>> {x: x*x for x in range(10)}
    {0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81}
    

    Python 3 下的列表推导:

    >>> list(x*x for x in range(10))
    [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
    
    >>> [x*x for x in range(10)]
    [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
    

    在 Python 2 中,列表推导式不仅仅是语法糖。但唯一的区别是 x 在 Python 2 下会泄漏到命名空间中。

    >>> x
    9
    

    在 Python 3 下你会得到 ​​p>

    >>> x
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    NameError: name 'x' is not defined
    

    这意味着在 Python 中获得生成器表达式内容的良好打印输出的最佳方法是对其进行列表推导!但是,如果您已经有生成器对象,这显然不起作用。这样做只会列出一个生成器:

    >>> foo = (x*x for x in range(10))
    >>> [foo]
    [<generator object <genexpr> at 0xb7559504>]
    

    在这种情况下,您需要致电list()

    >>> list(foo)
    [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
    

    虽然这可行,但有点愚蠢:

    >>> [x for x in foo]
    [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
    

    【讨论】:

    • 官方术语仍然是“生成器表达式”,因为“理解”这个词意味着迭代,这是 genexp 做的一件事,因为这个问题和答案很好地说明了:)
    • list( generator-expression ) 没有打印生成器表达式;它正在生成一个列表(然后在交互式外壳中打印它)。在 Python 3 中,您可以将生成器表达式转换为打印语句,而不是生成列表。即)print(*(generator-expression))。这将打印开头和结尾不带逗号且不带括号的元素。
    【解决方案5】:
    >>> list(x for x in string.letters if x in (y for y in "BigMan on campus"))
    ['a', 'c', 'g', 'i', 'm', 'n', 'o', 'p', 's', 'u', 'B', 'M']
    

    【讨论】:

    • 如果生成器是无限的,就会导致循环。
    猜你喜欢
    • 2022-01-07
    • 2017-12-08
    • 2018-07-06
    • 2014-04-02
    • 2021-12-27
    • 2014-09-24
    • 2021-10-17
    • 2012-08-20
    相关资源
    最近更新 更多