【问题标题】:Difference between chain(*iterable) vs chain.from_iterable(iterable)chain(*iterable) 与 chain.from_iterable(iterable) 之间的区别
【发布时间】:2016-09-16 13:44:41
【问题描述】:

我一直对itertools 中所有有趣的迭代器非常着迷,但我有一个困惑是这两个函数之间的区别以及chain.from_iterable 存在的原因。

from itertools import chain

def foo(n):
    for i in range(n):
        yield [i, i**2]

chain(*foo(5))

chain.from_iterable(foo(5))

这两个函数有什么区别?

【问题讨论】:

    标签: python itertools


    【解决方案1】:

    前者只能处理不可打包的迭代。后者可以处理无法完全解包的可迭代对象,例如无限生成器。

    考虑

    >>> from itertools import chain
    >>> def inf():
    ...     i=0
    ...     while True:
    ...         i += 1
    ...         yield (i, i)
    ... 
    >>> x=inf()
    >>> y=chain.from_iterable(x)
    >>> z=chain(*x)
    <hangs forever>
    

    此外,拆包是一项急切的预付费活动,因此,如果您的可迭代对象具有您想要延迟评估的效果,from_iterable 是您的最佳选择。

    【讨论】:

    • 顺便说一句,这个例子中的inf实际上和itertools.count是一样的
    • 这里的示例代码无论如何都不起作用; inf 不是可迭代的可迭代,它是标量的可迭代,因此只有 chain(x) 可以工作。 chain(*x) 确实更糟(它甚至无法成功拨打电话,chain.from_iterable(x) 会立即返回,并且只有在您向它请求值时才会以 TypeError 死掉),但这两个例子都很糟糕。 yield (i, i) 或其他东西会使这个例子变得理智。
    【解决方案2】:

    chain(*foo(5)) 解包整个生成器,将其打包成一个元组,然后对其进行处理。

    chain.from_iterable(foo(5)) 查询从foo(5) 值创建的生成器。

    尝试foo(1000000) 并观察内存使用量不断上升。

    【讨论】:

      【解决方案3】:

      * 解包迭代器,这意味着它迭代迭代器以便将其值传递给函数。 chain.from_iterable 懒惰地一一迭代迭代器。

      【讨论】:

        猜你喜欢
        • 2016-08-20
        • 2021-04-09
        • 2013-02-06
        • 2016-06-27
        • 2010-11-06
        • 2012-09-24
        • 1970-01-01
        • 1970-01-01
        • 2012-01-04
        相关资源
        最近更新 更多