I have been really fascinated by all the interesting iterators in itertools, but one confusion I have had is the difference between these two functions and why
itertools
chain(*foo(5)) unpacks the whole generator, packs it into a tuple and processes it then.
chain(*foo(5))
chain.from_iterable(foo(5)) queries the generator created from foo(5) value for value.
chain.from_iterable(foo(5))
foo(5)
Try foo(1000000) and watch the memory usage go up and up.
foo(1000000)