I could not find any valid example on the internet where I can see the difference between them and why to choose one over the other.
I could not find any valid example ... where I can see the difference between them [
chainandchain.from_iterable] and why to choose one over the other
The accepted answer is thorough. For those seeking a quick application, consider flattening several lists:
list(itertools.chain(["a", "b", "c"], ["d", "e"], ["f"]))
# ['a', 'b', 'c', 'd', 'e', 'f']
You may wish to reuse these lists later, so you make an iterable of lists:
iterable = (["a", "b", "c"], ["d", "e"], ["f"])
Attempt
However, passing in an iterable to chain gives an unflattened result:
list(itertools.chain(iterable))
# [['a', 'b', 'c'], ['d', 'e'], ['f']]
Why? You passed in one item (a tuple). chain needs each list separately.
Solutions
When possible, you can unpack an iterable:
list(itertools.chain(*iterable))
# ['a', 'b', 'c', 'd', 'e', 'f']
list(itertools.chain(*iter(iterable)))
# ['a', 'b', 'c', 'd', 'e', 'f']
More generally, use .from_iterable (as it also works with infinite iterators):
list(itertools.chain.from_iterable(iterable))
# ['a', 'b', 'c', 'd', 'e', 'f']
g = itertools.chain.from_iterable(itertools.cycle(iterable))
next(g)
# "a"