1025

How do I iterate between 0 and 1 by a step of 0.1?

This says that the step argument cannot be zero:

for i in range(0, 1, 0.1): print(i) 
5
  • 22
    int(0.1) == 0, so the step actually is zero. It may be unexpected, but it is zero. You might want to restate your question to reflect that fact that it's you didn't expect this. Saying "it's not" is false and misleading. Commented Jan 25, 2009 at 13:34
  • 3
    BTW A short one-liner can be rolled up using itertools.takewhile and itertools.count. It isn't better than drange performance-wise, though. Commented Nov 29, 2012 at 16:15
  • 4
    It's embarrassing that python's range dosen't allow this, given how easy it is to implement a generator that does this even without accumulating rounding errors. Heck, even the seq tool in GNU coreutils allows one to do seq 0 0.1 1 without rounding errors! Commented Aug 20, 2016 at 5:55
  • 3
    @josch: seq uses the C long double type internally, and is subject to rounding errors. For example on my machine, seq 0 0.1 1 gives 1 as its last output (as expected), but seq 1 0.1 2 gives 1.9 as the last output (rather than the expected 2). Commented Oct 24, 2017 at 18:39
  • 1
    For convenience, @Kos's suggestion can be implemented as itertools.takewhile(lambda x: (x+0.05)<1, itertools.count(0,0.1)) or itertools.islice(itertools.count(0,0.1), 10) (after you have import itertools), though I haven't tested which is more efficient Commented Sep 19, 2019 at 14:13

36 Answers 36

1235

Rather than using a decimal step directly, it's much safer to express this in terms of how many points you want. Otherwise, floating-point rounding error is likely to give you a wrong result.

Use the linspace function from the NumPy library (which isn't part of the standard library but is relatively easy to obtain). linspace takes a number of points to return, and also lets you specify whether or not to include the right endpoint:

>>> np.linspace(0,1,11) array([ 0. , 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1. ]) >>> np.linspace(0,1,10,endpoint=False) array([ 0. , 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]) 

If you really want to use a floating-point step value, use numpy.arange:

>>> import numpy as np >>> np.arange(0.0, 1.0, 0.1) array([ 0. , 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]) 

Floating-point rounding error will cause problems, though. Here's a simple case where rounding error causes arange to produce a length-4 array when it should only produce 3 numbers:

>>> numpy.arange(1, 1.3, 0.1) array([1. , 1.1, 1.2, 1.3]) 
Sign up to request clarification or add additional context in comments.

8 Comments

numpy is such an ubiquitous component of python that I consider this answer to be the most 'pythonic' of all.
@AndreTerra The problem is that @numpy@ is a third party package and adds a lot of overhead in terms of dependency-management, storage (for the package itself) etc. Depending on what the developer is doing, it may be impossible to use it.
Pardon me, but I didn't understand the floating point rounding error in the last part since np.linspace(1.,1.3,4) and np.arange(1.,1.3,0.1) give exactly the same output
@deadcode The reason is that np.arange is defined to produce a range [start,stop) (i.e. excluding stop), so one would not expect 1.3 to be included in the list. See this question for why it is still included and what to do against it.
How much a package is used is arguably not any indicator of whether it is "Pythonic."
|
307

range() can only do integers, not floating point.

Use a list comprehension instead to obtain a list of steps:

[x * 0.1 for x in range(0, 10)] 

More generally, a generator comprehension minimizes memory allocations:

xs = (x * 0.1 for x in range(0, 10)) for x in xs: print(x) 

8 Comments

Even better, you could just use a generator comprehension if you're working with Python 2.4+. (x * 0.1 for x in range(0, 10)).
Even better, put x/10 instead of x * 0.1 :D Nothing special actually, but some numbers in there will be more precise, e.g. for 3*0.1 you get 0.30000000000000004, while for 3/10 you get 0.3 :)
3/10 gives me 0, not 0.3. 3/10.0 gives 0.29999999999999999. Python 2.6.
@LarsWirzenius: in Python 2.2+, from __future__ import division; 3/10 returns 0.3. This behaviour is the default in Python 3.x.
round function can also be used lst = [round(x* 0.10,2) for x in range(0,10)]
|
160

Building on 'xrange([start], stop[, step])', you can define a generator that accepts and produces any type you choose (stick to types supporting + and <):

>>> def drange(start, stop, step): ... r = start ... while r < stop: ... yield r ... r += step ... >>> i0=drange(0.0, 1.0, 0.1) >>> ["%g" % x for x in i0] ['0', '0.1', '0.2', '0.3', '0.4', '0.5', '0.6', '0.7', '0.8', '0.9', '1'] >>> 

6 Comments

This has roundoff problems. Please look here: code.activestate.com/recipes/66472
I would extend it a bit for the other direction with a (while r > stop) and a corresponding r -= step for giving the opposite direction.
I did a xfrange function without the float precision problems referred above. Check it out ;) stackoverflow.com/questions/477486/…
You're accumulating rounding errors. Please use this instead: ` i = 0; r = start while r < stop: i += 1; r = start + i * step; yield r`
This is from pythoncentral.io/pythons-range-function-explained (and other Python documentation sources)
|
39

NumPy is a bit overkill, I think.

[p/10 for p in range(0, 10)] [0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9] 

Generally speaking, to do a step-by-1/x up to y you would do

x=100 y=2 [p/x for p in range(0, int(x*y))] [0.0, 0.01, 0.02, 0.03, ..., 1.97, 1.98, 1.99] 

(1/x produced less rounding noise when I tested).

1 Comment

Cleanest solution imo. List comprehension also makes it look very short and simple.
38

Increase the magnitude of i for the loop and then reduce it when you need it.

for i * 100 in range(0, 100, 10): print i / 100.0 

EDIT: I honestly cannot remember why I thought that would work syntactically

for i in range(0, 11, 1): print i / 10.0 

That should have the desired output.

3 Comments

I think you'll find that range() works off integers, in which case this would be the only solution, using the same function atleast.
@cmsjr creative :D Just one little thing: divide by 100.0 to keep Python from truncating the result if you're using Python 2.x. I think in 3.0, it'll work as you've coded it.
for i * 100 in range(0, 100, 10): SyntaxError: can't assign to operator
24

scipy has a built in function arange which generalizes Python's range() constructor to satisfy your requirement of float handling.

from scipy import arange

1 Comment

This is actually the exact same arange you can find in numpy: >>> import scipy >>> import numpy >>> numpy.arange is scipy.arange will return True.
22

Similar to R's seq function, this one returns a sequence in any order given the correct step value. The last value is equal to the stop value.

def seq(start, stop, step=1): n = int(round((stop - start)/float(step))) if n > 1: return([start + step*i for i in range(n+1)]) elif n == 1: return([start]) else: return([]) 

Results

seq(1, 5, 0.5) 

[1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0]

seq(10, 0, -1) 

[10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

seq(10, 0, -2) 

[10, 8, 6, 4, 2, 0]

seq(1, 1) 

[ 1 ]

4 Comments

This is a great answer for someone who wants to get it one without getting too much into python.
That was almost what I was looking for - note that seq(0.5, 3.0) returns [0.5, 1.5, 2.5, 3.5]. To avoid last entries being out-of-range, replace n = int(round(... with n = int(floor(... with the line from math import floor at the top (above def seq(...).
@FriendFX Don't do this! If floor is used, seq(0.2, 0.9, 0.1) will fail to reach right endpoint and will return [0.2, 0.30000000000000004, 0.4, 0.5, 0.6000000000000001, 0.7, 0.8]
@user502144: Nice catch, thanks. I guess I have to settle for one of the more complex solutions in order to keep it general.
17

The range() built-in function returns a sequence of integer values, I'm afraid, so you can't use it to do a decimal step.

I'd say just use a while loop:

i = 0.0 while i <= 1.0: print i i += 0.1 

If you're curious, Python is converting your 0.1 to 0, which is why it's telling you the argument can't be zero.

1 Comment

Don't do this! Adding .1 10 times is not the same as adding 1! docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
15

Here's a solution using itertools:

import itertools def seq(start, end, step): if step == 0: raise ValueError("step must not be 0") sample_count = int(abs(end - start) / step) return itertools.islice(itertools.count(start, step), sample_count) 

Usage Example:

for i in seq(0, 1, 0.1): print(i) 

1 Comment

For the sake of completeness, you should calculate the absolute value for the sample_count variable, that way your function will also work for a negative start (i.e from -10 to 10)
12
[x * 0.1 for x in range(0, 10)] 

in Python 2.7x gives you the result of:

[0.0, 0.1, 0.2, 0.30000000000000004, 0.4, 0.5, 0.6000000000000001, 0.7000000000000001, 0.8, 0.9]

but if you use:

[ round(x * 0.1, 1) for x in range(0, 10)] 

gives you the desired:

[0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]

Comments

10
import numpy as np for i in np.arange(0, 1, 0.1): print i 

1 Comment

this has the rounding issue, quote: "When using a non-integer step, such as 0.1, the results will often not be consistent." -- docs.scipy.org/doc/numpy/reference/generated/numpy.arange.html
7

Best Solution: no rounding error

>>> step = .1 >>> N = 10 # number of data points >>> [ x / pow(step, -1) for x in range(0, N + 1) ] [0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0] 

Or, for a set range instead of set data points (e.g. continuous function), use:

>>> step = .1 >>> rnge = 1 # NOTE range = 1, i.e. span of data points >>> N = int(rnge / step >>> [ x / pow(step,-1) for x in range(0, N + 1) ] [0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0] 

To implement a function: replace x / pow(step, -1) with f( x / pow(step, -1) ), and define f.
For example:

>>> import math >>> def f(x): return math.sin(x) >>> step = .1 >>> rnge = 1 # NOTE range = 1, i.e. span of data points >>> N = int(rnge / step) >>> [ f( x / pow(step,-1) ) for x in range(0, N + 1) ] [0.0, 0.09983341664682815, 0.19866933079506122, 0.29552020666133955, 0.3894183423086505, 0.479425538604203, 0.5646424733950354, 0.644217687237691, 0.7173560908995228, 0.7833269096274834, 0.8414709848078965] 

Comments

6

And if you do this often, you might want to save the generated list r

r=map(lambda x: x/10.0,range(0,10)) for i in r: print i 

Comments

6

more_itertools is a third-party library that implements a numeric_range tool:

import more_itertools as mit for x in mit.numeric_range(0, 1, 0.1): print("{:.1f}".format(x)) 

Output

0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 

This tool also works for Decimal and Fraction.

Comments

5

My versions use the original range function to create multiplicative indices for the shift. This allows same syntax to the original range function. I have made two versions, one using float, and one using Decimal, because I found that in some cases I wanted to avoid the roundoff drift introduced by the floating point arithmetic.

It is consistent with empty set results as in range/xrange.

Passing only a single numeric value to either function will return the standard range output to the integer ceiling value of the input parameter (so if you gave it 5.5, it would return range(6).)

Edit: the code below is now available as package on pypi: Franges

## frange.py from math import ceil # find best range function available to version (2.7.x / 3.x.x) try: _xrange = xrange except NameError: _xrange = range def frange(start, stop = None, step = 1): """frange generates a set of floating point values over the range [start, stop) with step size step frange([start,] stop [, step ])""" if stop is None: for x in _xrange(int(ceil(start))): yield x else: # create a generator expression for the index values indices = (i for i in _xrange(0, int((stop-start)/step))) # yield results for i in indices: yield start + step*i ## drange.py import decimal from math import ceil # find best range function available to version (2.7.x / 3.x.x) try: _xrange = xrange except NameError: _xrange = range def drange(start, stop = None, step = 1, precision = None): """drange generates a set of Decimal values over the range [start, stop) with step size step drange([start,] stop, [step [,precision]])""" if stop is None: for x in _xrange(int(ceil(start))): yield x else: # find precision if precision is not None: decimal.getcontext().prec = precision # convert values to decimals start = decimal.Decimal(start) stop = decimal.Decimal(stop) step = decimal.Decimal(step) # create a generator expression for the index values indices = ( i for i in _xrange( 0, ((stop-start)/step).to_integral_value() ) ) # yield results for i in indices: yield float(start + step*i) ## testranges.py import frange import drange list(frange.frange(0, 2, 0.5)) # [0.0, 0.5, 1.0, 1.5] list(drange.drange(0, 2, 0.5, precision = 6)) # [0.0, 0.5, 1.0, 1.5] list(frange.frange(3)) # [0, 1, 2] list(frange.frange(3.5)) # [0, 1, 2, 3] list(frange.frange(0,10, -1)) # [] 

2 Comments

How can frange work if stop is None? That part of the code doesn't even consider the step size anymore.
@josch range has two signatures: range(stop), which assumes a default start=0, step=1, and range(start, stop, step), where no assumptions are made. frange reflects that. When using the range(stop) signature, both frange and drange start at 0 and increment by 1, so their behaviour is identical to regular range(stop) behaviour with stop rounded up to the nearest integer.
5

Suprised no-one has yet mentioned the recommended solution in the Python 3 docs:

See also:

  • The linspace recipe shows how to implement a lazy version of range that suitable for floating point applications.

Once defined, the recipe is easy to use and does not require numpy or any other external libraries, but functions like numpy.linspace(). Note that rather than a step argument, the third num argument specifies the number of desired values, for example:

print(linspace(0, 10, 5)) # linspace(0, 10, 5) print(list(linspace(0, 10, 5))) # [0.0, 2.5, 5.0, 7.5, 10] 

I quote a modified version of the full Python 3 recipe from Andrew Barnert below:

import collections.abc import numbers class linspace(collections.abc.Sequence): """linspace(start, stop, num) -> linspace object Return a virtual sequence of num numbers from start to stop (inclusive). If you need a half-open range, use linspace(start, stop, num+1)[:-1]. """ def __init__(self, start, stop, num): if not isinstance(num, numbers.Integral) or num <= 1: raise ValueError('num must be an integer > 1') self.start, self.stop, self.num = start, stop, num self.step = (stop-start)/(num-1) def __len__(self): return self.num def __getitem__(self, i): if isinstance(i, slice): return [self[x] for x in range(*i.indices(len(self)))] if i < 0: i = self.num + i if i >= self.num: raise IndexError('linspace object index out of range') if i == self.num-1: return self.stop return self.start + i*self.step def __repr__(self): return '{}({}, {}, {})'.format(type(self).__name__, self.start, self.stop, self.num) def __eq__(self, other): if not isinstance(other, linspace): return False return ((self.start, self.stop, self.num) == (other.start, other.stop, other.num)) def __ne__(self, other): return not self==other def __hash__(self): return hash((type(self), self.start, self.stop, self.num)) 

1 Comment

The link is dead. What as the solution?
5

Lots of the solutions here still had floating point errors in Python 3.6 and didnt do exactly what I personally needed.

Function below takes integers or floats, doesnt require imports and doesnt return floating point errors.

def frange(x, y, step): if int(x + y + step) == (x + y + step): r = list(range(int(x), int(y), int(step))) else: f = 10 ** (len(str(step)) - str(step).find('.') - 1) rf = list(range(int(x * f), int(y * f), int(step * f))) r = [i / f for i in rf] return r 

3 Comments

Nice solution of v3.9 as well. Lack of imports is good. Cheers
If wanting the output list to be inclusive of the entire range, change to rf = list(range(int(x * f), int((y+step) * f), int(step * f)))
This is so good, except if you can make frange(end, start=0, step=1) and it will work similar to range
3

This is my solution to get ranges with float steps.
Using this function it's not necessary to import numpy, nor install it.
I'm pretty sure that it could be improved and optimized. Feel free to do it and post it here.

from __future__ import division from math import log def xfrange(start, stop, step): old_start = start #backup this value digits = int(round(log(10000, 10)))+1 #get number of digits magnitude = 10**digits stop = int(magnitude * stop) #convert from step = int(magnitude * step) #0.1 to 10 (e.g.) if start == 0: start = 10**(digits-1) else: start = 10**(digits)*start data = [] #create array #calc number of iterations end_loop = int((stop-start)//step) if old_start == 0: end_loop += 1 acc = start for i in xrange(0, end_loop): data.append(acc/magnitude) acc += step return data print xfrange(1, 2.1, 0.1) print xfrange(0, 1.1, 0.1) print xfrange(-1, 0.1, 0.1) 

The output is:

[1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0] [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1] [-1.0, -0.9, -0.8, -0.7, -0.6, -0.5, -0.4, -0.3, -0.2, -0.1, 0.0] 

3 Comments

There is an error with missing the last value if it is within 1 step of the stop value. i.e. xfrange(1,10,2) only does 1,3,5,7, missing 9
For reference and other readers, please compare this implementation to this stackoverflow.com/a/477610/54964. This does not seem to have big float problems.
@carlosvega Can you confirm why Lobe gets his result?
3

For completeness of boutique, a functional solution:

def frange(a,b,s): return [] if s > 0 and a > b or s < 0 and a < b or s==0 else [a]+frange(a+s,b,s) 

1 Comment

I can only image the recursion errors and overhead of this when python doesn't do tail-call optimization
2

You can use this function:

def frange(start,end,step): return map(lambda x: x*step, range(int(start*1./step),int(end*1./step))) 

3 Comments

Doesn't seem to work correctly, e.g. list(frange(99.8, 100.1, 0.1)) => [99.7, 99.80000000000001, 99.9]
@ShaiColeman That's general floating point rounding, not a flaw of this particular method. If you worry about this, several answers here contain workarounds; see perhaps also stackoverflow.com/questions/588004/…
@tripleee , It's wrong even ignoring the rounding errors. expected: [99.8, 99.9, 100.0] actual: [99.7, 99.8, 99.9]
2

It can be done using Numpy library. arange() function allows steps in float. But, it returns a numpy array which can be converted to list using tolist() for our convenience.

for i in np.arange(0, 1, 0.1).tolist(): print i 

Comments

2

start and stop are inclusive rather than one or the other (usually stop is excluded) and without imports, and using generators

def rangef(start, stop, step, fround=5): """ Yields sequence of numbers from start (inclusive) to stop (inclusive) by step (increment) with rounding set to n digits. :param start: start of sequence :param stop: end of sequence :param step: int or float increment (e.g. 1 or 0.001) :param fround: float rounding, n decimal places :return: """ try: i = 0 while stop >= start and step > 0: if i==0: yield start elif start >= stop: yield stop elif start < stop: if start == 0: yield 0 if start != 0: yield start i += 1 start += step start = round(start, fround) else: pass except TypeError as e: yield "type-error({})".format(e) else: pass # passing print(list(rangef(-100.0,10.0,1))) print(list(rangef(-100,0,0.5))) print(list(rangef(-1,1,0.2))) print(list(rangef(-1,1,0.1))) print(list(rangef(-1,1,0.05))) print(list(rangef(-1,1,0.02))) print(list(rangef(-1,1,0.01))) print(list(rangef(-1,1,0.005))) # failing: type-error: print(list(rangef("1","10","1"))) print(list(rangef(1,10,"1"))) 

Python 3.6.2 (v3.6.2:5fd33b5, Jul 8 2017, 04:57:36) [MSC v.1900 64 bit (AMD64)]

Comments

2

I know I'm late to the party here, but here's a trivial generator solution that's working in 3.6:

def floatRange(*args): start, step = 0, 1 if len(args) == 1: stop = args[0] elif len(args) == 2: start, stop = args[0], args[1] elif len(args) == 3: start, stop, step = args[0], args[1], args[2] else: raise TypeError("floatRange accepts 1, 2, or 3 arguments. ({0} given)".format(len(args))) for num in start, step, stop: if not isinstance(num, (int, float)): raise TypeError("floatRange only accepts float and integer arguments. ({0} : {1} given)".format(type(num), str(num))) for x in range(int((stop-start)/step)): yield start + (x * step) return 

then you can call it just like the original range()... there's no error handling, but let me know if there is an error that can be reasonably caught, and I'll update. or you can update it. this is StackOverflow.

1 Comment

As a warning, this solution doesn't implement the __contains__ operator, and depending on your use case, it could be very VERY slow to call if x in list(floatRange(a,b,c)):...
1

Add auto-correction for the possibility of an incorrect sign on step:

def frange(start,step,stop): step *= 2*((stop>start)^(step<0))-1 return [start+i*step for i in range(int((stop-start)/step))] 

1 Comment

A better designed library would throw an error instead of trying to correct the user's sign.
1

My solution:

def seq(start, stop, step=1, digit=0): x = float(start) v = [] while x <= stop: v.append(round(x,digit)) x += step return v 

Comments

1

Here is my solution which works fine with float_range(-1, 0, 0.01) and works without floating point representation errors. It is not very fast, but works fine:

from decimal import Decimal def get_multiplier(_from, _to, step): digits = [] for number in [_from, _to, step]: pre = Decimal(str(number)) % 1 digit = len(str(pre)) - 2 digits.append(digit) max_digits = max(digits) return float(10 ** (max_digits)) def float_range(_from, _to, step, include=False): """Generates a range list of floating point values over the Range [start, stop] with step size step include=True - allows to include right value to if possible !! Works fine with floating point representation !! """ mult = get_multiplier(_from, _to, step) # print mult int_from = int(round(_from * mult)) int_to = int(round(_to * mult)) int_step = int(round(step * mult)) # print int_from,int_to,int_step if include: result = range(int_from, int_to + int_step, int_step) result = [r for r in result if r <= int_to] else: result = range(int_from, int_to, int_step) # print result float_result = [r / mult for r in result] return float_result print float_range(-1, 0, 0.01,include=False) assert float_range(1.01, 2.06, 5.05 % 1, True) ==\ [1.01, 1.06, 1.11, 1.16, 1.21, 1.26, 1.31, 1.36, 1.41, 1.46, 1.51, 1.56, 1.61, 1.66, 1.71, 1.76, 1.81, 1.86, 1.91, 1.96, 2.01, 2.06] assert float_range(1.01, 2.06, 5.05 % 1, False)==\ [1.01, 1.06, 1.11, 1.16, 1.21, 1.26, 1.31, 1.36, 1.41, 1.46, 1.51, 1.56, 1.61, 1.66, 1.71, 1.76, 1.81, 1.86, 1.91, 1.96, 2.01] 

Comments

1

I am only a beginner, but I had the same problem, when simulating some calculations. Here is how I attempted to work this out, which seems to be working with decimal steps.

I am also quite lazy and so I found it hard to write my own range function.

Basically what I did is changed my xrange(0.0, 1.0, 0.01) to xrange(0, 100, 1) and used the division by 100.0 inside the loop. I was also concerned, if there will be rounding mistakes. So I decided to test, whether there are any. Now I heard, that if for example 0.01 from a calculation isn't exactly the float 0.01 comparing them should return False (if I am wrong, please let me know).

So I decided to test if my solution will work for my range by running a short test:

for d100 in xrange(0, 100, 1): d = d100 / 100.0 fl = float("0.00"[:4 - len(str(d100))] + str(d100)) print d, "=", fl , d == fl 

And it printed True for each.

Now, if I'm getting it totally wrong, please let me know.

Comments

1

The trick to avoid round-off problem is to use a separate number to move through the range, that starts and half the step ahead of start.

# floating point range def frange(a, b, stp=1.0): i = a+stp/2.0 while i<b: yield a a += stp i += stp 

Alternatively, numpy.arange can be used.

Comments

1

My answer is similar to others using map(), without need of NumPy, and without using lambda (though you could). To get a list of float values from 0.0 to t_max in steps of dt:

def xdt(n): return dt*float(n) tlist = map(xdt, range(int(t_max/dt)+1)) 

Comments

1

To counter the float precision issues, you could use the Decimal module.

This demands an extra effort of converting to Decimal from int or float while writing the code, but you can instead pass str and modify the function if that sort of convenience is indeed necessary.

from decimal import Decimal def decimal_range(*args): zero, one = Decimal('0'), Decimal('1') if len(args) == 1: start, stop, step = zero, args[0], one elif len(args) == 2: start, stop, step = args + (one,) elif len(args) == 3: start, stop, step = args else: raise ValueError('Expected 1 or 2 arguments, got %s' % len(args)) if not all([type(arg) == Decimal for arg in (start, stop, step)]): raise ValueError('Arguments must be passed as <type: Decimal>') # neglect bad cases if (start == stop) or (start > stop and step >= zero) or \ (start < stop and step <= zero): return [] current = start while abs(current) < abs(stop): yield current current += step 

Sample outputs -

from decimal import Decimal as D list(decimal_range(D('2'))) # [Decimal('0'), Decimal('1')] list(decimal_range(D('2'), D('4.5'))) # [Decimal('2'), Decimal('3'), Decimal('4')] list(decimal_range(D('2'), D('4.5'), D('0.5'))) # [Decimal('2'), Decimal('2.5'), Decimal('3.0'), Decimal('3.5'), Decimal('4.0')] list(decimal_range(D('2'), D('4.5'), D('-0.5'))) # [] list(decimal_range(D('2'), D('-4.5'), D('-0.5'))) # [Decimal('2'), # Decimal('1.5'), # Decimal('1.0'), # Decimal('0.5'), # Decimal('0.0'), # Decimal('-0.5'), # Decimal('-1.0'), # Decimal('-1.5'), # Decimal('-2.0'), # Decimal('-2.5'), # Decimal('-3.0'), # Decimal('-3.5'), # Decimal('-4.0')] 

5 Comments

WIth similar Decimal inputs, np.arange works the same: np.arange(Decimal('-2.0'), Decimal('2.0'), Decimal('0.1'))
Yep, thanks. Although, that would need an external (numpy) lib.
I'd appreciate if you can provide feedback or reason for the downvote.
Questions about downvotes are pointless, since voters aren't notified, and hance rarely see them. I was notified based on a 2 year old comment.
Sorry to ping you, hoped it won't since I didn't tag. And yeah, my comment was just hopeful.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.