Py­thon is, as in­dic­ated by of­fi­cial py­thon tu­torial, the first doc­u­ment most Py­thon new­bies en­coun­ter, a dy­nam­ic­ally typed lan­guage. While de­vel­op­ing I learned to not worry about small de­tails and let duck typ­ing to do it’s thing.

The prob­lem

Un­der­stand­ing the pur­pose of range is a simple mat­ter. You give it point at which you want your arith­metic pro­gres­sion ter­min­ate and op­tion­ally what num­ber your se­quence should be­gin with and amount by which every con­sec­ut­ive num­ber in the se­quence should in­crease.

>>> list(range(0, 10, 3))
    [0, 3, 6, 9]

All is fine and good un­til you de­cide you want your se­quence to in­crease in steps of 110\frac{1}{10}. I shall try it out by simply passing a 0.1 as last ar­gu­ment.

>>> range(0, 1, 0.1)
    Traceback (most recent call last):
    File "<input>", line 1, in <module>
    TypeError: 'float' object cannot be interpreted as an integer

Strangely enough this be­ha­viour is in­ten­tional and there are no traces of code to sup­port any kind of dy­nam­ism for this func­tion. The reason of course is per­form­ance. Oth­er­wise nobody would use them in their highly op­tim­ised, tight loops, right? On the other hand in­ac­cur­acy of some data types as poin­ted out by Stack­Over­flow com­munity might be yet an­other reas­on.


Now, in case you do not have any prob­lems with pulling in whole numpy lib­rary as a de­pend­ency you can use numpy.arange. Oth­er­wise you might sim­u­late it with list com­pre­hen­sions or map:

>>> [x / 10 for x in range(0, 10)]
    [0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]
>>> list(map(lambda x: fractions.Fraction(x, 10), range(0, 10)))
    [Fraction(0, 1), Fraction(1, 10), Fraction(1, 5), Fraction(3, 10),
     Fraction(2, 5), Fraction(1, 2), Fraction(3, 5), Fraction(7, 10),
     Fraction(4, 5), Fraction(9, 10)]

This solu­tion is func­tional and terse, however, it is neither con­veni­ent nor beau­ti­ful. Py­thon could do bet­ter job here! A wrap­per func­tion us­ing reg­u­lar range given in­tegers and fall­ing back to slower code for everything else sounds reas­on­able. At least people would not need to map over val­ues to get them in form they need.