Учитывая список l=[1,2]
Я пытаюсь создать продукт перестановок. Другими словами, я пытаюсь создать следующее.
from itertools import permutations
l=[1,2]
print([(e1, e2) for e1 in permutations(l) for e2 in permutations(l)])
Приведенный выше код печатает [((1, 2), (1, 2)), ((1, 2), (2, 1)), ((2, 1), (1, 2)), ((2, 1), (2, 1))]
, как и ожидалось.
Однако, если я использую приведенный ниже код,
from itertools import permutations
l=[1,2]
lp1 = permutations(l)
lp2 = permutations(l)
print([(e1, e2) for e1 in lp1 for e2 in lp2])
Код печатается [((1, 2), (1, 2)), ((1, 2), (2, 1))]
.
Я предполагаю, что это связано с тем, что lp1
и lp2
указывают на один и тот же итератор. Но я не понимаю, почему это так. Это задуманное поведение или это ошибка?
Да. permutation
— генератор. Вы можете использовать его только один раз.
Чтобы проиллюстрировать это на более простом примере, это точно так же, как если бы вы пытался
for i in range(3):
for j in enumerate([1,2,3]):
print(i,j)
Получить
0 (0, 1)
0 (1, 2)
0 (2, 3)
1 (0, 1)
1 (1, 2)
1 (2, 3)
2 (0, 1)
2 (1, 2)
2 (2, 3)
А потом были удивлены, что
range1=range(3)
range2=enumerate([1,2,3])
for i in range1:
for j in range2:
print(i,j)
не работал должным образом и выдает:
0 (0, 1)
0 (1, 2)
0 (2, 3)
Потому что вам нужно воссоздавать range2
для каждой i
итерации. В противном случае j
with выполняет итерацию только один раз. В двух других случаях итератор закончился.
(Примечание редактирования: изначально я использовал range(3)
в своем примере для range2
. Но это не очень хороший пример, поскольку диапазон — это диапазон, а не генератор. Поэтому вы можете использовать его несколько раз)
Другой, более простой способ увидеть это:
r=itertools.permutations([1,2])
list(r)
list(r)
В первый раз он дает ожидаемый список. Содержит все, что генерирует генератор `permutations([1,2]).
Во второй раз выдает пустой список. Потому что генератору больше нечего генерировать.
Спасибо за объяснение! Я забыл, что lp2 исчерпан после первой итерации, моя вина.
Так и должно быть, потому что permutations() дает вам генератор перестановок. Как только вы пройдете через него, он исчерпается и больше не будет генерировать никаких элементов. Перестановки 0,1 — это 0,1 и 1,0, которые вам предоставят оба генератора. Следовательно, во втором варианте вы получите ровно четыре элемента.
Однако в первом примере вы создаете перестановку снова и снова для каждой итерации первой перестановки. Таким образом, код снова пройдет через вторые перестановки, в результате чего список станет более длинным.
Разница между двумя примерами заключается в следующем:
[(e1, e2) for e1 in permutations(l) for e2 in permutations(l)] # ^^^^^^^^^^^^^^^
Здесь для каждого permutations(l)
создается новый e1
.
lp2 = permutations(l) [(e1, e2) for e1 in lp1 for e2 in lp2])
Здесь для каждого lp2
повторно используется один и тот же e1
, но он исчерпывается после первого раза.
lp1 = permutations(l) lp2 = permutations(l)
[…]
Я предполагаю, что это связано с тем, что
lp1
иlp2
указывают на один и тот же итератор.
Нет, lp1
и lp2
— разные итераторы.
Ответы прояснили проблему, но в виде капсулы: в исходной версии
permutations()
вызывается три раза: один раз дляe1
и дважды дляe2
. Поэтому итератор во второй версии исчерпывается.