Backwards Ranges in Python

In Python, if you want to specify a sequence of numbers from a up to (but excluding) b, you can write range(a, b). This generates the sequence a, a+1, a+2, ..., b-1. You start at a and keep going until the next number would be b.

In Python 3, range is lazy and the values in the sequence do not materialize until you consume the range.

>>> range(3,12)
range(3, 12)
>>> list(range(3,12))
[3, 4, 5, 6, 7, 8, 9, 10, 11]

Trey Hunner makes the point that range is a lazy iterable rather than an iterator.

You can also step by an increment other than one: range(a, b, s). This generates a, a+s, a+2*s, ..., b-s (assuming that (b - a) % s == 0; i.e., a and b are separated by an exact multiple of s.)

>>> list(range(3, 12, 3))
[3, 6, 9]

What if you want to count down? range(b, a, -s) won't do what you want.

>>> list(range(12,3, -3))
[12, 9, 6]

Why? Because you're starting at b, a value that doesn't appear in the forward range, and you're ending before you reach a, a value that is certainly in the forward range. You have to subtract s from both b and a:

When you use range(b-s, a-s, -s), you get b-s, b-2*s, ..., a+s, a.

>>> list(range(12-3,3-3, -3))
[9, 6, 3]
>>> list(range(12-3,3-3, -3)), list(reversed(range(3, 12, 3)))
([9, 6, 3], [9, 6, 3])