Skip to content

Instantly share code, notes, and snippets.

@nicolasdespres
Created March 8, 2017 08:14
Show Gist options
  • Save nicolasdespres/fed915518cfcdb5c4dad73409eec77ea to your computer and use it in GitHub Desktop.
Save nicolasdespres/fed915518cfcdb5c4dad73409eec77ea to your computer and use it in GitHub Desktop.
Python iterator to cycle over a range
class cycle_range(Iterator):
"""Like `itertools.cycle` but on a range.
Since it works on a range it requires no extra memory contrary to
the standard `itertools.cycle`.
Examples:
>>> list(cycle_range(2, times=3))
[0, 1, 0, 1, 0, 1]
Args:
r: a range object or an integer
times: the number of cycle to do (0 for infinitely)
"""
def __init__(self, r, times=0):
if not isinstance(times, int):
raise TypeError("times must be int, not {}"
.format(type(times).__name__))
if times < 0:
raise ValueError("times must be positive or null, not {}"
.format(times))
self._range = as_range(r)
self._size = len(self._range)
self._times = times
self._len = self._size * self._times
self.reset()
def __len__(self):
"""Return the total number of iteration."""
return self._len
@property
def size(self):
"""Return the number of iteration per cycle."""
return self._size
@property
def times(self):
"""Return the number of cycle."""
return self._times
def _new_iterator(self):
self._it = iter(self._range)
def reset(self):
"""Reset the iterator to its initial state."""
self._new_iterator()
self._i = 1
def __next__(self):
while True:
try:
obj = next(self._it)
except StopIteration:
if self._i < self._times:
self._new_iterator()
self._i += 1
else:
raise StopIteration
else:
return obj
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment