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

How should I create an iterator that also supports a tell() method?

我需要创建一个 class,它 return 使用迭代器协议从数据流中一次一个字符,但它也有一个类似于文件对象的方法 tell(), return正在查看它当前在流中的位置。

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

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

最符合 pythonic 的方法是什么?我能以某种方式使用生成器来实现吗,还是我必须创建一个实现迭代器协议 "by hand" 的 class? (即 class 和 __next__() 方法在数据用完时手动引发 StopIteration

请注意,这个问题有点简化了我的实际需求。我实际上需要 tell()-模拟到 return 流位置的函数,而不仅仅是位置,所以请不要告诉我 "just make the caller of my iterator use enumerate()" 或类似的东西。

Can I do it using a generator somehow

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

or do I have to create a class that implements the iterator protocol "by hand"? (i.e. a class with a __next__() method that manually raises StopIteration when it runs out of data)

是也不是。是的,您必须创建一个迭代器 class,但这并不意味着您必须手动引发 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 a la 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

如果计算它的成本不是太高,让迭代器产生值和位置。或者,提供两种迭代方法,一种只产生值,另一种产生值和位置。