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.