Чтобы ответить на ваш вопрос, нам нужно взглянуть на реализацию itertools.product :
def product(*args, repeat=1):
pools = [tuple(pool) for pool in args] * repeat
result = [[]]
for pool in pools:
result = [x+[y] for x in result for y in pool]
for prod in result:
yield tuple(prod)
здесь вы найдете реальную реализацию C, но чтобыЧтобы ответить на этот вопрос, достаточно сослаться на python (см. ДОПОЛНИТЕЛЬНЫЙ абзац внизу).
сосредоточиться на этой строке кода:
pools = [tuple(pool) for pool in args] * repeat
таким образом, все элементыдва итератора (взятые во входных данных) преобразуются в список кортежей (только при первом вызове next()
), и в это время они фактически создаются.
Возвращаясь к вашему коду, когда вы вызываетеnext(l)
впервые созданы все элементы итераторов. В вашем примере будет создан список polls
со следующими элементами:
# pools: [(0, 1, 2), (0, 1, 2)]
, поэтому вы получили эти выходные данные.
Что касается print("Here")
Чтобы понять, почему он печатается первым, вам нужно понять, как работают генераторы:
itertool.product()
возвращает объект генератора. Генератор не выполняет код функции, пока он не будет стимулирован первым next()
. Впоследствии каждый вызов next()
позволяет вычислять следующий элемент, выполняя только один раз цикл, содержащий ключевое слово yield
.
Здесь вы найдете отличные ресурсы, чтобы лучше понять, как работает pythonгенераторы работают.
Почему 'itertools' решил сохранить список кортежей в памяти?
Поскольку декартово произведение должно оценивать один и тот же элемент несколько раз, и вместо этого итераторы не могут бытьпотребляется только один раз.
EXTRA
в C списке кортежей пулов он создан эквивалентно python, как вы можете видеть из этого кода, оцениваютсяс нетерпением. Каждый повторяемый аргумент сначала преобразуется в кортеж:
pools = PyTuple_New(npools);
if (pools == NULL)
goto error;
for (i=0; i < nargs ; ++i) {
PyObject *item = PyTuple_GET_ITEM(args, i);
PyObject *pool = PySequence_Tuple(item);
if (pool == NULL)
goto error;
PyTuple_SET_ITEM(pools, i, pool);
indices[i] = 0;
}
for ( ; i < npools; ++i) {
PyObject *pool = PyTuple_GET_ITEM(pools, i - nargs);
Py_INCREF(pool);
PyTuple_SET_ITEM(pools, i, pool);
indices[i] = 0;
}