Представьте, что вам нужно пробежать за один проход по N коллекциям, например по двум вот таким.

In [2]: l1 = list(range(5))

In [3]: l2 = list(range(10))

In [4]: l1
Out[4]: [0, 1, 2, 3, 4]

In [5]: l2
Out[5]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

Естественно, возникает желание написать вот такой цикл:

for i in l1+l2: print(i, end=", ")
# 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,

Проблема с этим решением в том, что вы создаете новый лист, и его длина равна сумме длин исходных листов. Если вы знаете, что они оба маленькие, то это, скорее всего, ничего, но представьте, что каждый весит в памяти по 1 Гб. В пике ваша программа съест в 2 раза больше памяти, чем весят ваши исходные листы. И легко может вообще не выполниться, если на машине не хватит RAM.

На самом деле, мы хотим сделать что-то вроде такого:

def gen(l1, l2):
    yield from l1
    yield from l2

for i in gen(l1,l2): print(i, end=", ")
# 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,

То есть не делать новых листов и ничего не копировать - а пробежать по ним по очереди, но через один итератор.

И это именно то, что делает itertools.chain

import itertools

for i in itertools.chain(l1,l2): print(i, end=", ")
# 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,

У чейна есть вторая форма, itertools.chain.from_iterable. Это абсолютно тоже самое, но с немного другим интерфейсом.

for i in itertools.chain.from_iterable([l1, l2]): print(i, end=", ")
# 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,

То есть, в общем виде:

#  это itertools.chain
In [5]: def my_chain(*collections):
...:     for collection in collections:
...:         yield from collection

#  это itertools.chain.from_iterable
In [8]: def my_chain_from_iterable(collections):
...:     for collection in collections:
...:         yield from collection

Стоило ли делать 2 чейна, отличающихся на анпэкинг аргументов? Не знаю, не мне судить авторов itertools, они боги. Но я знаю, что нет нужды плодить сущности без необходимости. А это возвращает нас к теме создания лишних новых листов и вообще лишних объектов.

Это я к чему?

Берегите ресурсы. Кажется, все уже давно не так и в наш век ресурсов сколько угодно, но после первого инвойса из Google Cloud Functions (где вы платите за использованные циклы CPU и мегабайто-часы съеденной памяти) уверен, Вы передумаете. Да и сам по себе питон не слишком экономичен - не стоит ему еще дополнительно помогать.

Что еще почитать?

Доки itertools

Бритва Оккама

Наш телеграм канал - так Вы никогда не пропустите очередную порцию философских размышлений на полчаса над 5 строчками кода.