如何在Python中创建一个像xrange一样的重复生成器?例如,如果我执行以下操作:
我两次都得到了相同的结果——数字0..4。然而,如果我尝试使用yield:
第二次尝试迭代m时,我什么也没有得到 - 一个空列表。
是否有一种简单的方法创建像xrange一样的重复生成器,使用yield或生成器理解?我在Python跟踪问题上找到了一个解决方法,它使用装饰器将生成器转换为迭代器。这会在每次开始使用它时重新启动,即使上次没有使用所有值,就像xrange一样。我还想出了自己的装饰器,基于相同的想法,它实际上返回一个生成器,但可以在抛出StopIteration异常后重新启动:
有没有更好的方法来解决这个问题,只使用yield和/或生成器推导?或者Python内置了什么东西?所以我不需要自己编写类和装饰器?
更新 u0b34a0f6ae的评论准确指出了我的误解的根源:
xrange(5)并不返回迭代器,它创建了一个xrange对象。xrange对象可以像字典一样被迭代多次。
我的“永恒”函数完全走错了路,表现得像一个迭代器/生成器(__iter__返回self),而不是像一个集合/xrange(__iter__返回一个新的迭代器)。
>>> m = xrange(5)
>>> print list(m)
>>> print list(m)
我两次都得到了相同的结果——数字0..4。然而,如果我尝试使用yield:
>>> def myxrange(n):
... i = 0
... while i < n:
... yield i
... i += 1
>>> m = myxrange(5)
>>> print list(m)
>>> print list(m)
第二次尝试迭代m时,我什么也没有得到 - 一个空列表。
是否有一种简单的方法创建像xrange一样的重复生成器,使用yield或生成器理解?我在Python跟踪问题上找到了一个解决方法,它使用装饰器将生成器转换为迭代器。这会在每次开始使用它时重新启动,即使上次没有使用所有值,就像xrange一样。我还想出了自己的装饰器,基于相同的想法,它实际上返回一个生成器,但可以在抛出StopIteration异常后重新启动:
@decorator.decorator
def eternal(genfunc, *args, **kwargs):
class _iterable:
iter = None
def __iter__(self): return self
def next(self, *nargs, **nkwargs):
self.iter = self.iter or genfunc(*args, **kwargs):
try:
return self.iter.next(*nargs, **nkwargs)
except StopIteration:
self.iter = None
raise
return _iterable()
有没有更好的方法来解决这个问题,只使用yield和/或生成器推导?或者Python内置了什么东西?所以我不需要自己编写类和装饰器?
更新 u0b34a0f6ae的评论准确指出了我的误解的根源:
xrange(5)并不返回迭代器,它创建了一个xrange对象。xrange对象可以像字典一样被迭代多次。
我的“永恒”函数完全走错了路,表现得像一个迭代器/生成器(__iter__返回self),而不是像一个集合/xrange(__iter__返回一个新的迭代器)。
xrange()
不是一个生成器。type(xrange(4))
!=type(myxrange(4))
。 - John Millikin