Nov-09-2019, 06:07 AM
i would like to make a generator (or modify an existing one) to have a means to reset it to start all over at the beginning (whether it has finished or not). how would i go about doing that without making a new one?
__iter__()
and __next__()
methods and the latter raises StopIteration when the iterator is exhausted. For exampleclass WalkList: def __init__(self, seq): if not isinstance(seq, list): raise TypeError('list argument expected, got', type(seq)) self.seq = seq self.reset() def reset(self): self.ite = iter(self.seq) def __next__(self): return next(self.ite) def __iter__(self): return self walk = WalkList(list(range(7))) r = True for item in walk: if r and item == 3: walk.reset() r = False continue print(item)
Output:λ python3 paillasse/genstate.py
0
1
2
0
1
2
3
4
5
6
__next__()
suppose to raise StopIteration when the generator is exhausted? or do you expect next()
to do that for you? would that mean self.ite
is being updated as this iterates? if not, where is next()
looking to know when it reaches the end?next()
at line 12 will raise StopIteration at the end of the iteration.Skaperen Wrote:what i am wanting is for there to be some extra callable that causes the generator to reset during its iteration
flag.set(False)
which returns True if the flag was previously set to True by another part of the code. Thus one can interfere with the inner mecanism of the generatorclass Flag: """An object with a boolean member 'value'""" def __init__(self): self.value = False def set(self, value): """Sets our value to a new value and return the old value""" result = self.value self.value = value return result def mygen(flag): while True: for i in range(10): if flag.set(False): # if the flag was set to True, we reset the generator break yield i else: break # test code spam = True flag = Flag() for i in mygen(flag): if spam and i == 3: flag.set(True) # this is how we tell the generator to reset itself spam = False print(i)Another solution would be to use a generator as a coroutine by using the syntax
y = yield x
, but I think it's much harder to manage.Output:0
1
2
3
0
1
2
3
4
5
6
7
8
9
y = yield x
work? i've never seen anything like that.@resetable
. To define a resetable generator, you only need to add a first argument 'self' and you can call self.reset()
inside the generator.from functools import wraps class Resetable: def __init__(self): self.flag = False self.iterator = None def reset(self, value=True): result = self.flag self.flag = bool(value) return result def __iter__(self): return self.iterator def resetable(gen): @wraps(gen) def wrapper(*args, **kwargs): r = Resetable() r.iterator = gen(r, *args, **kwargs) return r return wrapper @resetable def mygen(self, n): while True: for i in range(n): if self.reset(False): break yield i else: break if __name__ == '__main__': spam = True gen = mygen(7) for i in gen: if spam and i == 3: gen.reset() spam = False print(i)I haven't tried this but in recent versions of python, you should be able to write
for i in (gen := mygen(7)): ...
instead of defining gen on the previous line.(Nov-13-2019, 06:13 AM)Gribouillis Wrote: [ -> ]To learn about it, you could start with this page by David Beazley.