On Tue, Jun 28, 2016 at 11:58 AM, Grant Edwards <grant.b.edwa...@gmail.com> wrote: > On 2016-06-28, Tim Chase <python.l...@tim.thechases.com> wrote: >> On 2016-06-29 01:20, Steven D'Aprano wrote: >>> While loops are great for loops where you don't know how many >>> iterations there will be but you do know that you want to keep >>> going while some condition applies: >>> >>> while there is still work to be done: >>> do some more work >> >> I find this particularly the case when the thing being iterated over >> can be changed, such as a queue of things to process: >> >> items = deque() >> items.append(root_node) >> while items: >> item = items.popleft() >> process(item) >> items.extend(item.children) > > Yep, I often do something similar when processing a block of data > bytes comprising a sequence of "things" of varying number of bytes. > > data = read_a_blob_of_bytes() > while data: > #figure out how long the first "thing" is > len = <some expression typically involving the first few bytes of > 'data'> > handle_thing(data[:len]) > data = data[len:] >> But then, if you wrap up your "while" loop as a generator that yields >> things, you can then use it in a "for" loop which seems to me like >> the Pythonic way to do things. :-) > > Yea, I keep telling myself that, but I never actually do it.
Here you go: import collections class MutableIterator: def __init__(self, iterable): self._stopped = False self.replace(iterable) def __iter__(self): return self def __next__(self): if self._stopped: raise StopIteration while self._iterator or self._iterables: if self._iterator: try: return next(self._iterator) except StopIteration: self._iterator = None if self._iterables: self._iterator = iter(self._iterables.popleft()) self._stopped = True raise StopIteration def clear(): self._iterables.clear() self._iterator = None def replace(self, iterable): self._check_stopped() self._iterables = collections.deque([iterable]) self._iterator = None def append(self, item): self.extend([item]) def extend(self, iterable): self._check_stopped() self._iterables.append(iterable) def _check_stopped(self): if self._stopped: raise ValueError('Tried to mutate a stopped iterator') # Example: >>> mi = MutableIterator('bananas') >>> for char in mi: ... if char == 'a': ... mi.extend(' yum') ... print(char, end='') ... bananas yum yum yum -- https://mail.python.org/mailman/listinfo/python-list