# Python range() Function

The python `range()` function creates a collection of numbers on the fly, like 0, 1, 2, 3, 4. This is very useful, since the numbers can be used to index into collections such as string. The range() function can be called in a few different ways.

## range(n) - 1 Parameter Form

The most common form is `range(n)`, for integer n, which returns a numeric series starting with 0 and extending up to but not including n, e.g. `range(5)` returns `0, 1, 2, 3, 4`. Or put another way, `range(n) returns a series of `n` numbers, starting with `0`. This is perfect for generating the index numbers into, for example, a string..

```>>> s = 'Python'
>>> len(s)
6
>>> for i in range(len(s)):
...   print(i, s[i])
...
0 P
1 y
2 t
3 h
4 o
5 n
```

Below are some more examples calling range(). For cosmetic reasons in the examples below, the call of the range() function is inside a list() so the numbers will print out. This use of list() is only for printing, not needed to use range() in a loop.

```>>> list(range(5))
[0, 1, 2, 3, 4]
>>> list(range(10))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> list(range(2))
[0, 1]
```

What is `range(0)`? Well `range(n)` returns `n` numbers, so this case returns no numbers at all - like the empty list.

```>>> list(range(2))
[0, 1]
>>> list(range(1))
[0]
>>> list(range(0))   # n <= 0, no numbers
[]
>>> list(range(-42))
[]
```

## reversed() Variation

Probably the second most common problem is to go through the standard index numbers, but in reverse order. The `reversed()` function takes in a linear collection and returns a reversed form of it. This works nicely with range() to go over the regular numbers in reverse order:

```>>> s = 'Python'
>>> len(s)
6
>>> for i in reversed(range(len(s))):
...   print(i, s[i])
...
5 n
4 o
3 h
2 t
1 y
0 P
```

## range(start, stop) - 2 Parameter Form

Range with 2 parameters specifies a start number other than 0, but is otherwise like the 1 parameter form above, going up to but not including the stop number.

```>>> list(range(5, 10))
[5, 6, 7, 8, 9]
>>> list(range(5, 7))
[5, 6]
>>> list(range(5, 6))
[5]
>>> list(range(5, 5))  # start >= stop, no numbers
[]
>>> list(range(0, 5))
[0, 1, 2, 3, 4]
>>> list(range(0, 0))
[]
>>> list(range(0, -1))
[]
```

Mnemonic: the "stop" number is strong, so as soon as the numbers hit or exceed the stop the range is done (even if the start number initiates things in that position).

## range(start, stop, step) - 3 Parameter Form

The 3 parameter form begins with start number, up to but no including the stop number as usual. The difference is the "step" amount between numbers is now custom. Once the number is equal or goes beyond the stop, the range ends. As before, the stop number itself is always omitted.

```>>> list(range(0, 10, 2))
[0, 2, 4, 6, 8]
>>> list(range(0, 10, 6))
[0, 6]
>>> list(range(200, 800, 100))
[200, 300, 400, 500, 600, 700]
```

If the step is negative, the range decreases from start down to stop. As always, numbers reaching or beyond the stop are omitted, but now step is decreasing.

```>>> list(range(10, 5, -1))
[10, 9, 8, 7, 6]
>>> list(range(10, 5, -2))
[10, 8, 6]
>>> list(range(6, 5, -2))
[6]
>>> list(range(5, 5, -2))  # equal to stop is omitted
[]
>>> list(range(4, 5, -2))  # beyond the stop is omitted
[]
```

If you want to loop over the index numbers of a string or list backwards, it's easier to use `reversed()` above, vs. trying to do it manually with a negative increment.