Join us and get access to hundreds of tutorials and a community of expert Pythonistas.

Unlock This Lesson

This lesson is for members only. Join us and get access to hundreds of tutorials and a community of expert Pythonistas.

Unlock This Lesson

Hint: You can adjust the default video playback speed in your account settings.
Hint: You can set the default subtitles language in your account settings.
Sorry! Looks like there’s an issue with video playback 🙁 This might be due to a temporary outage or because of a configuration issue with your browser. Please see our video player troubleshooting guide to resolve the issue.

Advanced Uses of range()

Give Feedback

So far, you’ve seen how you can use the range function to generate a list of integers. It might appear that using range() in a for loop is equivalent to using a list of incrementing or decrementing values, but that’s not the case. There are some important similarities and differences. range() is its own class in Python:

>>>
>>> type(range(3))
<class 'range'>

range isn’t a list, but it dynamically manages a list in memory.

00:00 So far, we’ve seen how we can use the range() function to generate a list of integers. It would appear that using range() in a for loop is equivalent to using a list of incrementing or decrementing values—but that’s actually not the case.

00:20 There are some important similarities and differences. To explain them, I’m going to use the interactive shell.

00:28 I’ve been saying that the range() function generates a list of numbers, which is true, but it’s not the same as just having a list. To prove this, I’ll use the type() function, passing in a call to range().

00:47 As you can see, range is its own class in Python. range is clearly not a list, but instead it dynamically manages a list in memory.

01:01 Even though range itself isn’t an iterable type, we can still use common indexing and slicing techniques as if it were an iterable. For example, I can say range(3) and get the element at index 1, which is 1. Now take a look at this.

01:25 I’m going to slice a range like this, range(6) from 2 to 5. This is the same way we would slice a string or a list in Python, but this probably wasn’t what you were expecting. Rather than exposing the underlying list, slicing a range just returns another range that can generate the list we need.

01:54 But why does this even matter? One word: performance. In Python 3, range() is lazy, which means that it generates new values on a need-by-need basis, rather than when execution reaches the range() call.

02:13 If the whole list of numbers isn’t needed by our program, it isn’t stored in memory, which can result in some noticeable performance improvements in very large programs.

02:25 If we want to force the range() function to spit out the underlying list, we can simply pass it in to the built-in list() function just like this.

02:37 Back in Python 2, things used to be a little bit different. range() would generate the numbers all at once and xrange() would generate the numbers lazily.

02:51 In Python 3, range() replaces the old xrange(), and xrange() no longer exists.

Become a Member to join the conversation.