Python has two handy functions for creating lists, or a *range* of integers that assist in making `for`

loops.

These functions are `xrange`

and `range`

. But you probably already guessed that!

# The Difference Between xrange and range in Python

Before we get started, let's talk about what makes `xrange`

and `range`

different.

For the most part, `xrange`

and `range`

are the exact same in terms of functionality. They both provide a way to generate a list of integers for you to use, however you please. The only difference is that `range`

returns a Python `list`

object and `xrange`

returns an `xrange`

object.

What does that mean? Good question! It means that `xrange`

doesn't actually generate a static list at run-time like `range`

does. It creates the values as you need them with a special technique called *yielding*. This technique is used with a type of object known as *generators*. If you want to read more in depth about generators and the yield keyword, be sure to checkout the article Python generators and the yield keyword.

Okay, now what does *that* mean? Another good question. *That* means that if you have a really gigantic range you'd like to generate a list for, say one billion, `xrange`

is the function to use. This is especially true if you have a really memory sensitive system such as a cell phone that you are working with, as `range`

will use as much memory as it can to create your array of integers, which can result in a `MemoryError`

and crash your program. It's a memory hungry beast.

That being said, if you'd like to iterate over the list multiple times, it's probably better to use `range`

. This is because `xrange`

has to generate an integer object every time you access an index, whereas `range`

is a static list and the integers are already "there" to use.

Alright, now on to the good stuff.

# How to Use Python's range and xrange

So how do we use `range`

and `xrange`

? Here is the simplest example:

1 2 3 4 5 6 7 8 9 10 11 12 13 |
>>> for i in xrange(10): ... print(i) ... 0 1 2 3 4 5 6 7 8 9 |

Great! Simple enough. Note that you could also use `range`

in place of `xrange`

here, but I personally like `xrange`

better. Maybe it's that sexy "x" in the front.

Alright, explanation time. The functions `xrange`

and `range`

take in three arguments in total, however two of them are optional. The arguments are "start", "stop" and "step". "start" is what integer you'd like to start your list with, "stop" is what integer you'd like your list to stop at, and "step" is what your list elements will increment by.

## Python's xrange and range with Odd Numbers

Say we wanted only odd numbers. Here's what we could do:

1 2 3 4 5 6 7 8 |
>>> for i in xrange(1, 10, 2): ... print(i) ... 1 3 5 7 9 |

We told Python that we would like the first element to be one, the last element to be one less than ten, and that we'd like each element to go up by two. Really simple stuff.

## Python's xrange and range with Negative Numbers

Alright, so what about if we want a negative list?

Simple. Here's an example:

1 2 3 4 5 6 7 8 9 10 11 12 |
>>> for i in xrange(-1, -10, -1): ... print(i) ... -1 -2 -3 -4 -5 -6 -7 -8 -9 |

That's it! All we have to do is change the "start", "stop" and "step" to negative numbers. Awesome. Please note that you must do it this way for negative lists. Trying to use `xrange(-10)`

will not work because `xrange`

and `range`

use a default "step" of one.

## Another Python xrange and range Example

Here's one more example of even numbers between 100 and 120:

1 2 3 4 5 6 7 8 9 10 11 12 13 |
>>> for i in xrange(100, 120, 2): ... print(i) ... 100 102 104 106 108 110 112 114 116 118 |

And that's pretty much it for `xrange`

and `range`

. If you would like a more technical explanation of what these two functions do, please consult the Python docs for xrange and range.

Note that if "start" is larger than "stop", the list returned will be empty. Also, if "step" is larger that "stop" minus "start", then "stop" will be raised to the value of "step" and the list will contain "start" as its only element.

Here's a clearer picture:

1 2 3 4 5 6 7 8 |
>>> for i in xrange(70, 60): ... print(i) ... # Nothing is printed >>> for i in xrange(10, 60, 70): ... print(i) ... 10 |

# Deprecation of Python's xrange

One more thing to add. In Python 3.x, the `xrange`

function does not exist anymore. The `range`

function now does what `xrange`

does in Python 2.x, so to keep your code portable, you might want to stick to using `range`

instead. Of course, you could always use the 2to3 tool that Python provides in order to convert your code, but that introduces more complexity.

The reason why `xrange`

was removed was because it is basically always better to use it, and the performance effects are negligible. So Python 3.x's `range`

function *is* `xrange`

from Python 2.x.

You can find the PEP document here for reasoning why it was removed.

Over and out, soldier. Over and out.