2016-05-01 4 views
1

Рассмотрите этот код, в котором я использую combinations и попытаюсь сделать список из них.Почему вызывающий список() на iterable меняет его?

from itertools import combinations 

t = (1,2,3,4) 
print("t is %r" % (t,)) 
print("list(t) is %r" % list(t)) 
print("list(t) is %r" % list(t)) 

t2 = ("a", "b", "c", "d") 
print("t2 is %r" % (t2,)) 

combs = combinations(t2, 2) 
print("List of combinations of t2: %r" % list(combs)) 
print("List of combinations of t2: %r" % list(combs)) 

Выход (неожиданно для меня)

t is (1, 2, 3, 4) 
list(t) is [1, 2, 3, 4] 
list(t) is [1, 2, 3, 4] 
t2 is ('a', 'b', 'c', 'd') 
List of combinations of t2: [('a', 'b'), ('a', 'c'), ('a', 'd'), ('b', 'c'), ('b', 'd'), ('c', 'd')] 
List of combinations of t2: [] 

Итак, ясно, list() имеет побочные эффекты. Как и ожидалось, преобразование кортежа в список не изменяет исходные данные, я могу сделать это несколько раз. Но когда я пытаюсь сделать то же самое с итерабельным, возвращаемым с combinations, это работает только один раз, а затем итерируемый, по-видимому, недействителен. Делает ли list вызов next на итеративном так, что после того, как это будет сделано, итератор будет в конце или почему это произойдет? И как я могу избежать этого?

+0

'combination' - это функция генератора, которую вы можете перебирать только один раз. Вызов 'list' на нем исчерпывает его ... – schwobaseggl

ответ

3

itertools.combinations создает ленивый генератор, а не полную структуру данных, которая сохраняется в памяти. Как только вы исчерпаете его (перебираете через него) с чем-то вроде list(), это ... хорошо, измученный. Пустой. Если вы хотите использовать его повторно, сохранить ссылку:

combs = list(combinations(t2, 2)) 
print("List of combinations of t2: %r" % combs) 
print("List of combinations of t2: %r" % combs) 
0

Как вы верно подметили, list разрушительно, как генератор может быть исчерпан только один раз. Простое решение заключается в использовании itertools.tee:

>>> c1, c2 = itertools.tee(itertools.combinations(["a", "b", "c"], 2)) 
>>> print(list(c1)) 
... will print the entire sequence of combinations 
>>> print(list(c2)) 
... same as before 

Это может быть больше памяти консерватор, как проведение на весь список, так как itertools.tee нужно только держать на элементы, которые не потребляются всеми итераторы.

Смежные вопросы