Sto cercando un modo per "sfogliare" un iteratore Python. Cioè, mi piacerebbe racchiudere un dato iteratore iter e page_size con un altro iteratore che restituirebbe gli elementi da iter come una serie di "pagine". Ogni pagina sarebbe essa stessa un iteratore con un massimo di page_size iterazioni.Come scrivere un cercapersone per gli iteratori Python?
Ho guardato attraverso itertools e la cosa più vicina che ho visto è itertools.islice. In un certo senso, quello che mi piacerebbe è il contrario di itertools.chain - invece di concatenare una serie di iteratori in un unico iteratore, mi piacerebbe rompere un iteratore in una serie di iteratori più piccoli. Mi aspettavo di trovare una funzione di paging in itertools ma non ho potuto individuarne una.
Mi è venuta in mente la seguente classe di cercapersone e dimostrazione.
class pager(object):
"""
takes the iterable iter and page_size to create an iterator that "pages through" iter. That is, pager returns a series of page iterators,
each returning up to page_size items from iter.
"""
def __init__(self,iter, page_size):
self.iter = iter
self.page_size = page_size
def __iter__(self):
return self
def next(self):
# if self.iter has not been exhausted, return the next slice
# I'm using a technique from
# https://stackoverflow.com/questions/1264319/need-to-add-an-element-at-the-start-of-an-iterator-in-python
# to check for iterator completion by cloning self.iter into 3 copies:
# 1) self.iter gets advanced to the next page
# 2) peek is used to check on whether self.iter is done
# 3) iter_for_return is to create an independent page of the iterator to be used by caller of pager
self.iter, peek, iter_for_return = itertools.tee(self.iter, 3)
try:
next_v = next(peek)
except StopIteration: # catch the exception and then raise it
raise StopIteration
else:
# consume the page from the iterator so that the next page is up in the next iteration
# is there a better way to do this?
#
for i in itertools.islice(self.iter,self.page_size): pass
return itertools.islice(iter_for_return,self.page_size)
iterator_size = 10
page_size = 3
my_pager = pager(xrange(iterator_size),page_size)
# skip a page, then print out rest, and then show the first page
page1 = my_pager.next()
for page in my_pager:
for i in page:
print i
print "----"
print "skipped first page: " , list(page1)
Sto cercando un feedback ed ho le seguenti domande:
- C'è un pager già itertools che serve un cercapersone che sto con vista?
- La clonazione di self.iter 3 volte sembra triste per me. Un clone è per verificare se self.iter ha altri elementi. Ho deciso di andare con a technique Alex Martelli suggested (consapevole che ha scritto di un wrapping technique). Il secondo clone consisteva nell'abilitare che la pagina restituita fosse indipendente dall'iteratore interno (self.iter). C'è un modo per evitare di creare 3 cloni?
- Esiste un modo migliore per gestire l'eccezione StopIteration a seguito dell'acquisizione e del successivo sollevamento? Sono tentato di non prenderlo affatto e farlo esplodere.
Grazie! -Raymond
correlati: http://stackoverflow.com/questions/312443/how-do-you-split-a-list-into-evenly-sized-chunks-in-python http://stackoverflow.com/questions/434287/what-is-the-most-pythonic-way-to-iterate-over-a-list-in-chunks http://stackoverflow.com/questions/1335392/iteration-over-list-slices http : //stackoverflow.com/questions/760753/iterate-over-a-python-sequence-in-multiples-of-n – jfs