我应该如何创建一个也支持tell()方法的迭代器?

时间:2015-09-01 04:56:26

标签: python iterator generator

我需要创建一个类,它使用迭代器协议从数据流中一次返回一个字符,但是它也有一个类似于文件对象tell()的方法,返回什么位置它目前在流中。

基本上,这就是我需要的:

>>> x = MyIterator('abcdefghijklmnopqrstuvwxyz')
>>> x.tell()
0
>>> next(x)
'a'
>>> next(x)
'b'
>>> next(x)
'c'
>>> x.tell()
3
>>> next(x)
'd'
>>> x.tell()
4

最狡猾的方式是什么?我可以用某种方式使用生成器来做,或者我是否必须创建一个实现迭代器协议的类"手动"? (即具有__next__()方法的类,当数据用完时手动引发StopIteration

请注意,这个问题有点简化了我的实际需求。我实际上需要tell() - analogue来返回流位置的函数,而不仅仅是位置,所以请不要告诉我"只是让我的迭代器的调用者使用{{1} }"或类似的东西。

2 个答案:

答案 0 :(得分:3)

  

我可以用某种方式使用发生器吗

不是真的。 (理论上你可以通过将计数器存储为生成器函数的函数属性来实现,但是尝试使函数引用自身是一个冒险的命题。)

  

还是我必须创建一个“手动”实现迭代器协议的类? (即具有__next__()方法的类,当数据用完时手动引发StopIteration)

是和否。是的,您必须创建一个迭代器类,但这并不意味着您必须手动提升StopIteration。假设您希望迭代器包装一些可迭代的源,那么您可以依靠该源来引发StopIteration。这是一个简单的例子:

class MyIter(object):
    def __init__(self, source):
        self.source = iter(source)
        self.counter = 0

    def next(self):
        self.counter += 1
        return next(self.source)

    def __iter__(self):
        return self

    def tell(self):
        return self.counter

(这使用next和Python 2;对于Python 3,您必须将def next更改为def __next__。)

然后:

>>> x = MyIter('abc')
>>> for item in x:
...     print(item, x.tell())
a 1
b 2
c 3

答案 1 :(得分:1)

如果计算它并不太昂贵,请让迭代器同时产生值和位置。或者,提供两种迭代方法,一种只产生值,另一种产生值和位置。