steptools
steptools.range is as a drop-in replacement for range, adding with
support for anything that behaves reasonably like a number, including
floats, datetime.datetime, datetime.date, fractions.Fraction, and
decimal.Decimal.
if stop is None, start will be used as stop and start will be “zero”
created with type(start)().
Similar to range, generated items are EXCLUSIVE of stop.
inclusive=True allows stop to be returned, assuming it’s a multiple
of step.
type(step)() should construct a “zero” version of step which has no result
if added to start. If this does not work, set zero_step explicitly.
Examples
steptools.range can act as a drop-in replacement for range to iterate over ints. range is probably faster!
>>> list(range(3))
[0, 1, 2]
>>> list(range(3, inclusive=True))
[0, 1, 2, 3]
>>> list(range(5, -3, -2))
[5, 3, 1, -1]
>>> list(range(1.1, 1.5, .2))
[1.1, 1.3]
steptools.range can iterate over over datetime.datetime and
datetime.date objects using a datetime.timedelta as the step.
>>> from datetime import datetime, timedelta
>>> list(range(datetime(2000, 1, 1), datetime(1999,12,30),
... timedelta(days=-1)))
[datetime.datetime(2000, 1, 1, 0, 0), datetime.datetime(1999, 12, 31, 0, 0)]
steptools.range can iterate over over fractions.Fraction
>>> from fractions import Fraction
>>> list(range(Fraction(1,3), Fraction(2,3), Fraction(1,6)))
[Fraction(1, 3), Fraction(1, 2)]
>>> list(range(Fraction(1,3), Fraction(5,3)))
[Fraction(1, 3), Fraction(4, 3)]
steptools.range can iterate over over decimal.Decimal
>>> from decimal import Decimal
>>> list(range(Decimal("1.33"), Decimal("1.66"), Decimal("0.11")))
[Decimal('1.33'), Decimal('1.44'), Decimal('1.55')]
Requirements
steptools does not depend on any non-core libraries, however the values you pass in for start, stop, step, and zero_step must have certain behavior. The following should all work reasonably without raising exception. The comparisons (< and ==) should return a bool.:
if zero_step is None:
type(step)() # must be logically "zero"
step == zero_step
if step < zero_step:
stop < start
stop < (start+step)
else:
start < stop
(start+step) < stop
if inclusive:
start == stop
(start+step) == stop
if stop is none:
type(start)() # must be logically "zero"