Difference between chain(*iter) vs chain.from_iterable(iter)
<p>I have been really fascinated by all the interesting iterators in itertools and one confusion I have had is the difference between these two functions and why chain.from_iterator exists.</p>

<pre><code>from itertools import chain

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

chain(*foo(5))

chain.from_iterable(foo(5))
</code></pre>

<p>What is the difference between the two functions?</p>

<p>The former can only handle unpackable iterables. The latter can handle iterables that cannot be fully unpacked, such as infinite generators.</p>

<p>Consider</p>

<pre><code>&gt;&gt;&gt; from itertools import chain
&gt;&gt;&gt; def inf():
...     i=0
...     while True:
...         i += 1
...         yield i
... 
&gt;&gt;&gt; x=inf()
&gt;&gt;&gt; y=chain.from_iterable(x)
&gt;&gt;&gt; z=chain(*x)
&lt;hangs forever&gt;
</code></pre>

<p>Furthermore, just the act of unpacking is an eager, up-front-cost activity, so if your iterable has effects you want to evaluate lazily, <code>from_iterable</code> is your best option.</p>

python