chain(*iterable) 与 chain.from_iterable(iterable) 之间的区别
Posted
技术标签:
【中文标题】chain(*iterable) 与 chain.from_iterable(iterable) 之间的区别【英文标题】:Difference between chain(*iterable) vs 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))
这两个函数有什么区别?
【问题讨论】:
【参考方案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
懒惰地一一迭代迭代器。
【讨论】:
以上是关于chain(*iterable) 与 chain.from_iterable(iterable) 之间的区别的主要内容,如果未能解决你的问题,请参考以下文章
为啥chain.from_iterable 不遍历int 列表?
from itertools import chain:使用详解
chain.from_iterable实现同时walk多个目录