Это не генерирует перестановки. Генерирует n-мерные декартовы произведения. (При этом он также генерирует все перестановки, но алгоритм генерации только перестановок будет другим.)
Немного сложно объяснить, как это работает, но если вы посмотрите на вывод для небольшого ввода, вы сможете увидеть, что происходит. Рассмотрим выходные данные для 'abc'
и [None] * 3
(я изменил код, чтобы он действовал как настоящий генератор):
>>> def generate(charlist,state,position):
... for i in charlist:
... state[position] = i
... if position == (len(state)-1):
... yield "".join(state)
... else:
... for j in generate(charlist,state,position+1):
... yield j
...
>>> print list(generate('abc', [None] * 3, 0))
['aaa', 'aab', 'aac', 'aba', 'abb', 'abc', 'aca', 'acb', 'acc',
'baa', 'bab', 'bac', 'bba', 'bbb', 'bbc', 'bca', 'bcb', 'bcc',
'caa', 'cab', 'cac', 'cba', 'cbb', 'cbc', 'cca', 'ccb', 'ccc']
Как видите, вначале generate
вызывает себя три раза, увеличивая position
каждый раз (с 0
до 1
до 2
). Каждый раз в цикле рекурсии он помещает 'a'
в текущую позицию и проверяет, достиг ли он конца списка state
. Если это так, он дает результат и не вызывает себя.
В этом случае, когда это произойдет, position == 2
. Теперь включается цикл for
, сохраняя 'b'
и 'c'
в state[2]
и приводя к каждому из этих состояний. Затем функция завершается, и управление возвращается вызывающей стороне, для чего position == 1
. Вызывающий затем продолжает цикл for; он устанавливает state[1] = 'b'
, а затем, поскольку position
больше не находится в конце списка state
, он снова вызывает себя ... теперь position == 2
и наборы циклов for state[2] == 'a'
, 'b'
, 'c'
и т. Д.
Кстати, если вы хотите вычислить декартовы произведения в python, вот хороший способ, который не требует от ваших читателей разбора рекурсивного алгоритма:
>>> import itertools
>>> [''.join(c) for c in itertools.product('abc', 'abc', 'abc')]
['aaa', 'aab', 'aac', 'aba', 'abb', 'abc', 'aca', 'acb', 'acc',
'baa', 'bab', 'bac', 'bba', 'bbb', 'bbc', 'bca', 'bcb', 'bcc',
'caa', 'cab', 'cac', 'cba', 'cbb', 'cbc', 'cca', 'ccb', 'ccc']
Вы могли бы также сделать
>>> [''.join(c) for c in itertools.product(*['abc'] * 3)]