Python Ranges

If you've used Python for any length of time on the Pi, it's almost certain that you've come across range. Python's range is simply that: a range of values meeting certain criteria.

Range accepts three arguments:

  • Start - The number to start from
  • Stop - The number to stop at, not included in the range
  • Step - The step size of the range

Differences between Python 2 and Python 3

Range is one of the many gotchas in the transition between Python 2 and 3. Here's why:

In Python 2 a range returns a list:

>>> range(0,5)
[0, 1, 2, 3, 4]

In Python 2, the range function will immediately figure out every single number contained within the range you've asked for and will return it as a list.

In Python 3 a range returns an "virtual sequence of numbers":

>>> range(0,5)
range(0, 5)

Seeing the Python 2 method as wasteful, Python 3 changed range to use the "lazy way." Python 3's lazy ranges will only give you a value when asked for it, so if you do this:

>>> my_range = range(0,5)
>>> do_something_completely_different()

Python 3 simply wont waste time figuring out the values in my_range. In Python 2, however, it will go off and create a list at its leisure.

In most cases, you'll never run into anything on the Pi where the speed of lazy ranges versus ranges is a problem, or even a concern, but it's part of what helps make Python 3 faster and the lazy way is generally considered to be the right way amidst the programming neckbeards.

Ranges for fun and profit

So now you know exactly what a range is for, what can we do with it that matters to you? Let's practice some multiplication tables:

>>> def multiplication_table(table, results):
...     list(range(0,(table*results)-1,table))
...
>>> multiplication_table(3, 5)
[0, 3, 6, 9, 12]
>>> multiplication_table(7, 5)
[0, 7, 14, 21, 28]

Superb. We've now got a Python one liner for generating ranges we can practise with. Can we make it more useful?

def multiplication_table(number, number_of_items):
  return list(range(0, (number*(number_of_items+1)), number))[1:]

Ta daa:

>>> multiplication_table(9, 10)
[9, 18, 27, 36, 45, 54, 63, 72, 81, 90]

Reverse my range!

If you play with ranges for a while, you might find yourself trying something like this:

>>> list(range(9,0))
[]

Whoa? What happened there? Well the default value for the third argument of range is 1. If you try to count from 9 down to 0 by counting up 1 every time then you're going to have a very, very hard time getting there:

  • 9
  • 10 ?
  • 11 ... eek!
  • 12 ... this isn't going well
  • ...
  • 20 ... well, we've one one 0?

There's a simple fix for this:

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

This has an interesting side-effect:

  • If you create a range from 0 to 9 you'll get 0, 1, 2, 3, 4, 5, 6, 7, 8.
  • If you create a range from 9 to 0 you'll get 9, 8, 7, 6, 5, 4, 3, 2, 1.

You can either adjust your start/end accordingly, or optionally used the reversed function like so:

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

The reversed function will give you a reversed list, so you can count from 0 to 9 and then reverse it to get a countdown. reversed can also be used with lists, and isn't limited to just reversing lists of numbers.

What about xrange?

Unless you have a really, really good reason, don't use it. Let's ask Python 3 why:

>>> xrange(0,10)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'xrange' is not defined

In Python 3, range was updated to behave in the same way as xrange did in Python 2, rendering xrange obsolete. It's simply been removed.

xrange is one of those classic examples of language bloat, where things start to creep in that make sense but inevitably just complicate what's a really simple problem. In your Python adventures you're very unlikely to find an example where you're using exclusively Python 2 and need the extra performance that xrange can potentially offer. Stick with range and ensure your code will run in Python 3.

Shopping basket

Need something for this project? You can use the links below to add products to your Pimoroni Shop basket for easy checkout.

Raspberry Pi 3 with Pibow Case
Rainbow £44.00
Raspberry Pi 3 with Pibow Case
Ninja £44.00
Raspberry Pi 3 with Pibow Case
Ninja Coupé £40.00
Raspberry Pi 3 with Pibow Case
Coupé £40.00
Want to checkout or change something? Click here to view your cart.

Tutorial
Intermediate
Python

Phil Howard

phil@pimoroni.com
@gadgetoid
Phil is Pimoroni's software guru, instantly recognisable by his somewhat pirate-themed moustache growing attempts. Usually found buried neck deep in Python libraries, he's also been known to escape on occasion and turn out crazy new products. If you need a helping hand, he's a prolific Twitter user and rampages around the forums like a T-Rex. Ask him if you need help with Pimoroni's software libraries, or Propeller HAT.