重新启动消耗可再充装I的发电机

2024-09-26 18:06:41 发布

您现在位置:Python中文网/ 问答频道 /正文

我在使用使用可重复填充迭代器的生成器时遇到问题。在

这是我的简单发电机:

def hi(iterable):
  for val in iterable:
    yield val

我传递给hi生成器的iterable是来自functional_pipes repo的reservator类,该类在耗尽元素后可以重新填充。在

我想使用hi生成器,直到StopIteration被引发,然后重新填充iterable,然后像

^{pr2}$

但这个指纹

(1, 2, 3, 4)
()

第二个元组也应该是(5,6,7,8)。在

我找到了一个只有这个类的解决方案

def super_gener(function):
  class wrapper_class:
    def __init__(self, iterable):
      self.iterable = iterable
      self.zipped = None

    def __iter__(self):
      return self

    def __next__(self):
      try:
        return next(self.zipped)

      except TypeError:
        self.zipped = function(self.iterable)
        return next(self)

      except StopIteration as err:
        self.zipped = None
        raise err

  return wrapper_class

hi_iter = super_gener(hi)(refillable)

print(tuple(hi_iter))
refillable(data)
print(tuple(hi_iter))

这个解决方案似乎有点过分,我正在寻找一个更简单的解决方案。谢谢你的帮助。在

针对Ptank: 我不能将iterable保存到元组,因为iterable并不总是生成相同的项,并且在第二次填充refillable之前,这些项是未知的。在


Tags: selfreturndefval解决方案hiiterableclass
3条回答

因为生成器不是元组,所以生成的生成器是无内存的,只能读取一次。在

只需使用元组

def hi(iterable):
    return tuple(iterable)

您可以将hi更新为生成器工厂,并在每次使用时调用它。这比您当前的解决方案更干净,但可能由于其他原因而无法在您的案例中工作。在

def hi(iterable):
    def wrapper():
        for val in iterable:
            yield val
    return wrapper

与您当前使用的用法类似:

^{pr2}$

如果您想保持与原始示例完全相同的语法,可以创建一个类似的瘦类。在

class hi:
    def __init__(self, iterable):
        self.__iter__ = lambda: iterable

恐怕唯一的解决方案可能是创建一个可重复填充的生成器包装类。编辑:原始未测试的代码无法工作。我现在重构了下面的想法并进行了测试。在

此对象将引发StopIteration一次,之后将重新启动。它打算与Resettable修饰符一起使用,它将一个_func属性添加到类中。它应该具有与原始发电机相同的功能。在

class ResettableGenerator():
    '''Generator wrapper that is resettable.'''
    def __init__(self, *args, **kwargs):
        self.args = args
        self.kwargs = kwargs
        self.start()
    def __next__(self):
        n = self.send(None)
        return n
    def __iter__(self):
        yield from self._gen
    def start(self):
        self._gen = self._func(*self.args, **self.kwargs)
    def send(self, *args, **kwargs):
        try:
            n = self._gen.send(*args, **kwargs)
            return n
        except StopIteration:
            self.start()
            raise
    def throw(self, *args, **kwargs):
        self._gen.throw(*args, **kwargs)
    def close(self):
        self._gen.close()

这是装修师:

^{pr2}$

像这样使用:

@Resettable
def f():
    yield 1

现在你可以这样做:

>>> g=f()
>>> next(g)
1
>>> next(g)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 8, in __next__
  File "<stdin>", line 16, in send
StopIteration
>>> next(g)
1 #  generator has restarted itself

相关问题 更多 >

    热门问题