如何为Python迭代器编写寻呼机? [英] How to write a pager for Python iterators?

查看:151
本文介绍了如何为Python迭代器编写寻呼机?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在寻找一种浏览Python迭代器的方法。也就是说,我想用另一个迭代器包装一个给定的迭代器 iter page_size ,这个迭代器将把它作为一系列页面从iter返回。每个页面本身都是一个迭代器,最多包含 page_size 次迭代。

I'm looking for a way to "page through" a Python iterator. That is, I would like to wrap a given iterator iter and page_size with another iterator that would would return the items from iter as a series of "pages". Each page would itself be an iterator with up to page_size iterations.

我查看了 itertools 我最接近的是 itertools.islice 。在某些方面,我想要的是 itertools.chain - 而不是将一系列迭代器链接到一个迭代器中,我想将迭代器分解为一系列较小的迭代器。我期待在itertools中找到一个分页功能,但找不到。

I looked through itertools and the closest thing I saw is itertools.islice. In some ways, what I'd like is the opposite of itertools.chain -- instead of chaining a series of iterators together into one iterator, I'd like to break an iterator up into a series of smaller iterators. I was expecting to find a paging function in itertools but couldn't locate one.

我提出了以下的分页器类和演示。

I came up with the following pager class and demonstration.

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)   

我正在寻找一些反馈并提出以下问题:

I'm looking for some feedback and have the following questions:


  1. 是否已有寻呼机 itertools 提供我正在俯瞰的寻呼机?

  2. 克隆self.iter 3次对我来说似乎很糟糕。一个克隆是检查self.iter是否还有其他项目。我决定选择 Alex Martelli建议的一种技术(意识到他写了一篇包装技术)。第二个克隆是使返回的页面独立于内部迭代器( self.iter )。有没有办法避免制作3个克隆?

  3. 是否有更好的方法来处理 StopIteration 异常,除了捕获它然后再次提升它?我很想抓住它,让它冒出来。

  1. Is there a pager already in itertools that serves a pager that I'm overlooking?
  2. Cloning self.iter 3 times seems kludgy to me. One clone is to check whether self.iter has any more items. I decided to go with a technique Alex Martelli suggested (aware that he wrote of a wrapping technique). The second clone was to enable the returned page to be independent of the internal iterator (self.iter). Is there a way to avoid making 3 clones?
  3. Is there a better way to deal with the StopIteration exception beside catching it and then raising it again? I am tempted to not catch it at all and let it bubble up.

谢谢!
-Raymond

Thanks! -Raymond

推荐答案

你为什么不用这个?

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)来生成迭代器而不是对象,但我看不出它如何改善任何东西。

"Each page would itself be an iterator with up to page_size" items. Each page is a simple list of items, which is iterable. You could use yield iter(page) to yield the iterator instead of the object, but I don't see how that improves anything.

最后会抛出一个标准的 StopIteration

It throws a standard StopIteration at the end.

你还想要什么?

这篇关于如何为Python迭代器编写寻呼机?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆