Itertools.tee offers an interesting way to "remember" things that have happened. Itertools.tee makes multiple iterators from one (if you still have an the original iterator you do not use it). When you advance iterator 1 but not iterator 2, iterator 2 stays behind. Which means, if you later advance iterator 2, it the goes forward through the same data.
In this example, I use iterator.tee to make 2 iterators, to allow an action to affect data that has been processed in the past. The first iterator, it_main, is what is used to process data normally in this case to do something like display an image selected. The second iterator, it_history, stays behind the first and only advances when a specific action arrives. In effect, it rolls forward through the data that it_main has already processed.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | #there are all sorts of iterable objects in python nowadays
#for example, you can use itertools.tee on these:
iterable_obj=[1,2,3] #list
iterable_obj=( i for i in (1,2,3) ) #py 2.4 generator
iterable_obj=open('a.txt') #file handle
iterable_obj=os.popen('ls') #process to get dir listing
#also for an iterable function
def iterable_func():
for i in (1,2,3): yield i
#create 2 iterators
iterators = itertools.tee(iterable_obj)
#or for a function
iterators= itertools.tee(iterable_func())
#notice that you now have 2 iterable objects
print iterators
>>> (<itertools.tee object at 0x0089E040>, <itertools.tee object at 0x0089E050>)
#create 5 iterators
iterators=itertools.tee(iterable_obj,5)
###here is a trivial program that uses 2 iterators, where one iterator
###stays behind the other and advances on certain commands
import itertools
Saved=[]
Compressed=[]
def get_data():
data=['a.gif','b.gif','c.gif','save','e.gif','save']
data+=['f.gif','compress','g.gif','h.gif','i.gif','save']
for i in data: yield i
def display(image): print 'displaying',image
def move_to_present(history_it,action):
print '*Now doing action',action
for item in history_it:
if item in ('save','compress','reset'): break
if action=='save':
Saved.append(item)
elif action=='compress':
Compressed.append(item)
#reset just allows the iterator to move back to the front
#no other action needed
#make 2 iterators, it_history stays behind and moves forward
#whenever 'save' or 'compress' is received
it_main,it_history =itertools.tee(get_data())
for item in it_main:
if item in ('save','compress','reset'):
#move the history iterator forward to
#last iterator item displayed
move_to_present(it_history,item)
else:
display(item)
print 'Saved',Saved
print 'Compressed and Saved',Compressed
#running this results in:
>>> displaying a.gif
displaying b.gif
displaying c.gif
*Now doing action save
displaying e.gif
*Now doing action save
displaying f.gif
*Now doing action compress
displaying g.gif
displaying h.gif
displaying i.gif
*Now doing action save
Saved ['a.gif', 'b.gif', 'c.gif', 'e.gif', 'g.gif', 'h.gif', 'i.gif']
Compressed and Saved ['f.gif']
|
This is just one application of many that are possible when you have 2 separate pointers to the same stream of data. Rather than having to write your own code to keep track of data that you have processed, you can use iterator.tee to make an iterator to keep track of it for you.
For some solutions is can offer an elegant alternative. However, it does cost memory,is not selective, and consumes the data when moving forward. If you want to go back and forth or do not want keep a history of everything, iterator.tee may not be the right choice.
You can reach me at pyguy2 on yahoo.