如何为Python迭代器编写传呼器?

问题描述

你为什么不使用这个?

def grouper( page_size, iterable ):
    page= []
    for item in iterable:
        page.append( item )
        if len(page) == page_size:
            yield page
            page= []
    yield page

“每个页面本身都是一个迭代器,最多包含page_size个”项目。每个页面都是一个简单的项目列表,可以迭代。您可以使用它yield iter(page)来产生迭代器而不是对象,但是我看不出它会如何改善。

stopiteration在最后抛出一个标准。

您还想要什么?

解决方法

我正在寻找一种“页面遍历” Python迭代器的方法。也就是说,我想用另一个迭代器包装给定的迭代器 iterpage_size
,该迭代器将作为一系列“页面”从iter返回项目。每个页面本身就是一个迭代器,最多可进行 page_size 次迭代。

我浏览了itertools,发现最接近的东西是itertools.islice。在某些方面,我想要的是itertools.chain的反义词-
我不想将一系列迭代器链接在一起成为一个迭代器,而是希望将一个迭代器分解为一系列较小的迭代器。我期望在itertools中找到一个分页函数,但是找不到一个。

我提出了以下寻呼机课程和演示。

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)

我正在寻找一些反馈,并且有以下问题:

  1. itertools 中是否已经有一个寻呼机,可以为我所忽略的寻呼机提供服务?
  2. 对我而言,将self.iter克隆3次似乎很困难。一种克隆是检查self.iter是否还有更多项目。我决定采用Alex Martelli建议的技术(意识到他写过包装技术)。第二个克隆是使返回的页面独立于内部迭代器( self.iter )。有办法避免产生3个克隆吗?
  3. 除了捕获然后再次引发它之外,还有其他更好的方法来处理 StopIteration 异常吗?我很想根本不抓它,让它冒出来。

谢谢!-雷蒙德