Объяснение реализации Python itertools.product ()? - PullRequest
3 голосов
/ 05 апреля 2020

Как это Python волхвы c работает?

Код, о котором идет речь, взят из Python itertools.product документации :

def product(*args):
    pools = map(tuple, args)
    result = [[]]
    for pool in pools:
        result = [x+[y] for x in result for y in pool]
    for prod in result:
        yield tuple(prod)

Примечание : Да, я понимаю, что это не фактическая реализация. Кроме того, я удалил аргумент repeat, чтобы упростить код и сфокусировать обсуждение

Я понимаю , что делает приведенный выше код (его вывод), но я смотрю для объяснения как это работает. Я уже знаком со списками, включая вложенные for s.

Это особенно озадачивает:

for pool in pools:
    result = [x+[y] for x in result for y in pool]

Я пытался преобразовать вышеуказанный код в серию for зацикливается без какого-либо понимания списка, но я не могу получить правильные результаты. Этот тип алгоритма обычно требует рекурсии для обработки произвольного числа входных наборов. Отсюда мое заблуждение, что приведенный выше код, кажется, делает это итеративно.

Может кто-нибудь объяснить, как работает этот код?

1 Ответ

2 голосов
/ 05 апреля 2020

Вот список-преобразование, преобразованное в обычный for-l oop, если это поможет вам понять:

def product_nocomp(*args):
    pools = map(tuple, args)
    result = [[]]
    for pool in pools:
        _temp = []
        for x in result:
            for y in pool:
                _temp.append(x + [y])
        result = _temp
    for prod in result:
        yield tuple(prod)

А вот некоторые светящиеся print:

In [9]: def product_nocomp(*args):
   ...:     pools = list(map(tuple, args))
   ...:     result = [[]]
   ...:     print("Pools: ", pools)
   ...:     for pool in pools:
   ...:         print(result, end=' | ')
   ...:         _temp = []
   ...:         for x in result:
   ...:             for y in pool:
   ...:                 _temp.append(x + [y])
   ...:         result = _temp
   ...:         print(result)
   ...:     for prod in result:
   ...:         yield tuple(prod)
   ...:

In [10]: list(product_nocomp(range(2), range(2)))
Pools:  [(0, 1), (0, 1)]
[[]] | [[0], [1]]
[[0], [1]] | [[0, 0], [0, 1], [1, 0], [1, 1]]
Out[10]: [(0, 0), (0, 1), (1, 0), (1, 1)]

Таким образом, для каждого кортежа в пуле он проходит через каждый подсписок в промежуточном результате и добавляет каждый элемент в подсписок для каждого элемента в текущем пуле. Обратите внимание, что создает новые списки .

...