如何在Python中制作重复生成器(如xrange)?例如,如果我这样做:

>>> 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时,我什么也没回来-空列表。

有没有简单的方法来创建重复的生成器,例如带有yield的xrange或生成器理解?我找到了a workaround on a Python tracker issue,它使用装饰器将生成器转换为迭代器。每次您开始使用它时都会重新启动,即使您上次没有使用所有值也是如此,就像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内置的东西?因此,我不需要滚动自己的类和装饰器?

更新资料

comment by u0b34a0f6ae钉住了我的误解的根源:



我的“永恒”功能是通过像迭代器/生成器(__iter__返回self)而不是像collection / xrange(__iter__返回新的迭代器)来完全吠叫错误的树。

最佳答案

不直接。允许生成器用于实现协同例程,资源管理等的灵活性的一部分是,它们始终是一次性的。一旦运行,发电机将无法重新运行。您将必须创建一个新的生成器对象。

但是,您可以创建自己的覆盖__iter__()的类。它将像可重用的生成器一样工作:

def multigen(gen_func):
    class _multigen(object):
        def __init__(self, *args, **kwargs):
            self.__args = args
            self.__kwargs = kwargs
        def __iter__(self):
            return gen_func(*self.__args, **self.__kwargs)
    return _multigen

@multigen
def myxrange(n):
   i = 0
   while i < n:
     yield i
     i += 1
m = myxrange(5)
print list(m)
print list(m)

关于python - 如何在Python中制作重复生成器,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/1376438/

10-14 19:20