2016-05-01 14 views
1

Betrachten Sie diesen Code, in dem ich combinations verwende und versuche, eine Liste daraus zu machen.Warum ändert sich das Aufrufen von list() bei 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)) 

Der Ausgang ist (für mich unerwartet)

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: [] 

So klar, list() hat Nebenwirkungen. Wie erwartet, ändert die Konvertierung eines Tupels in eine Liste nicht die ursprünglichen Daten, ich kann es mehrmals tun. Aber wenn ich das gleiche mit einem iterierbaren von combinations zurückgegebenen versuche, funktioniert das nur einmal und dann ist das iterable anscheinend ungültig. Ruft listnext auf dem iterable, so dass nachdem es abgeschlossen ist, ist der Iterator am Ende oder warum passiert das? Und wie kann ich es vermeiden?

+0

'combinations' ist eine Generatorfunktion, die nur einmal durchlaufen werden kann. Wenn man 'liste' darauf aufruft, erschöpft es sich ... – schwobaseggl

Antwort

3

itertools.combinations erzeugt einen verzögerten Generator, keine vollständige Datenstruktur, die im Speicher gespeichert wird. Sobald Sie es mit etwas wie list() erschöpfen (iterieren), ist es ... nun, erschöpft. Leer. Wenn Sie es wollen, wiederholt verwenden, speichern eine Referenz:

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

Wie Sie richtig bemerkt haben, list destruktiv ist, als ein Generator nur einmal ausgeschöpft werden kann. Eine einfache Lösung ist itertools.tee zu verwenden:

>>> 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 

Dies kann auf die gesamte Liste als Holding auf mehr Speicher-konservativ sein, wie itertools.tee nur auf die Elemente zu halten, muss die nicht von allen Iteratoren verbraucht haben.

Verwandte Themen