2017-06-02 20 views
4

我使用使用可重複填充的迭代器的生成器時出現問題。重新啓動生成器使用可重複填充的迭代器

這裏是我的簡單發電機:

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

的迭代,我傳進喜發電機是它已經耗盡了它的元素之後,可重新裝填的functional_pipes repo水庫類。

我想消耗喜發電機直到StopIteration異常升高,然後重新填充迭代,然後再使用它像

refillable = Reservoir((1, 2, 3, 4)) 
hi_iter = hi(refillable) 

print(tuple(hi_iter)) 

refillable((5, 6, 7, 8)) 
print(tuple(hi_iter)) 

但這打印

(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: 我無法將迭代器保存到元組,因爲迭代器並不總是產生相同的項目,並且在再次填充第二次之前未知項目。

回答

1

恐怕唯一的解決辦法可能是創建一個可填充生成包裝類。編輯:原始未經測試的代碼不起作用。我現在重構了下面的想法並對其進行了測試。

此對象將一次性提起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() 

這裏是裝飾:

def Resettable(some_func): 
    cls = type(some_func.__name__, (ResettableGenerator,), {}) 
    cls._func = staticmethod(some_func) 
    return cls 

使用方法如下:

@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 
+0

感謝您的輸入!我喜歡這個裝飾器,它可以帶任何發生器。 –

0

因爲發電機不是Tuple,所以發電機產生的無記憶和只讀一次。

只需用一個元組

def hi(iterable): 
    return tuple(iterable) 
+0

我無法將迭代器保存到元組,因爲迭代器並不總是產生相同的項目,並且在再次填充第二次之前未知項目。 –

1

你也許能夠將hi更新爲屬tor工廠,每次你想使用它時都會打電話給它。這比您當前的解決方案更清潔,但由於其他原因可能無法在您的情況下工作。

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

類似用途爲您正在使用:

refillable = Reservoir((1, 2, 3, 4)) 
hi_iter = hi(refillable) 
print(tuple(hi_iter())) # (1, 2, 3, 4) 

refillable((5, 6, 7, 8)) 
print(tuple(hi_iter())) # (5, 6, 7, 8) 

如果你想保持完全相同的語法你原來的例子,你可以創建一個類似的細類。

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

感謝Jared的回答。不幸的是,我不能在大多數情況下重新定義我將使用的發生器。 –