If you’ve ever programmed in Python, you have a 96.2% chance of having used the `range()`

function. As you have a 96.1% chance of knowing, said function returns a list containing an arithmetic progression of integers, exactly as the documentation says. For example, `range(4)`

returns `[0, 1 2, 3]`

.

If you’ve ever bothered to look at the docstring, you will see that it goes thus:

```
range([start,] stop[, step]) -> list of integers
Return a list containing an arithmetic progression of integers.
range(i, j) returns [i, i+1, i+2, ..., j-1]; start (!) defaults to 0.
When step is given, it specifies the increment (or decrement).
For example, range(4) returns [0, 1, 2, 3]. The end point is omitted!
These are exactly the valid indices for a list of 4 elements.
```

Every reader will notice that there’s a mandatory parameter, `stop`

, and the rest are optional. The curious among you (or those who could be bothered to read it), will also notice, that the `start`

parameter **is optional**. How can this be? We all know that you can’t have optional keyword arguments before non-optional arguments in Python! What trickery does `range()`

use to do our bidding?

Luckily, after painstakingly downloading the source and poring through the 1221 lines of `rangeobject.c`

so you don’t have to, I now have the explanation of how such magic is performed. It’s really not very magical, and certainly nothing you can’t do in pure Python code.

Unlike my first instinct, it doesn’t use any fancy C magic to do that (well, it sort of does, but it’s just an implementation detail). How the range() function gets its optional first keyword argument is simple: The arguments aren’t keyword arguments at all:

```
>>> range(stop=2)
TypeError: range() takes no keyword arguments
```

After finding this out, it’s pretty easy to see how they got the optional first argument: They didn’t. They just check for the number of arguments passed and act accordingly. If there’s only one argument passed, it’s the `stop`

parameter, two are `start`

and `stop`

, and three are `start`

, `stop`

and `range`

.

I hope this foray into the Python source has taught you the valuable lesson it’s taught me: Don’t download the source before checking if the arguments actually **are** keyword arguments.

## Join the conversation!