Python tutorials > Core Python Fundamentals > Control Flow > What is `range()`?

What is `range()`?

The range() function is a built-in Python function that generates a sequence of numbers. It's commonly used in loops to iterate a specific number of times. It's versatile and plays a crucial role in various programming tasks.

Basic Usage

This code snippet demonstrates the most basic use of range(). It creates a sequence of numbers from 0 up to (but not including) 5. So the loop will execute 5 times, with i taking on the values 0, 1, 2, 3, and 4.

for i in range(5):
    print(i)

Specifying Start and Stop

Here, range(2, 7) creates a sequence starting from 2 and going up to (but not including) 7. The output will be 2, 3, 4, 5, and 6.

for i in range(2, 7):
    print(i)

Adding a Step

The third argument to range() is the step, which determines the increment between numbers. In this example, range(1, 10, 2) generates a sequence starting from 1, going up to (but not including) 10, and incrementing by 2 in each step. The output will be 1, 3, 5, 7, and 9.

for i in range(1, 10, 2):
    print(i)

Concepts Behind the Snippet

range() is a generator function, meaning it doesn't store the entire sequence in memory at once. Instead, it generates each number on demand as you iterate through it. This makes it memory-efficient, especially when dealing with large ranges.

The function returns an iterable range object. This object can be converted to a list or tuple if you need to store the entire sequence in memory (e.g., list(range(5))).

Real-Life Use Case

A common use case is iterating over the indices of a list. len(my_list) provides the length of the list, and range() generates a sequence of indices that can be used to access each element of the list.

my_list = ['apple', 'banana', 'cherry']
for i in range(len(my_list)):
    print(f'Index: {i}, Value: {my_list[i]}')

Best Practices

  • Use descriptive variable names (e.g., index instead of i when iterating through indices).
  • Avoid unnecessary conversions of the range object to a list, as this can impact performance for large ranges.
  • Consider using enumerate if you need both the index and the value of a sequence.

Interview Tip

Be prepared to discuss the memory efficiency of range() and its advantages over creating a full list when iterating. Understand the difference between range() in Python 2 and Python 3 (Python 2's range() creates a list, while Python 3's range() is a generator).

When to Use Them

Use range() when you need to iterate a fixed number of times or when you need to iterate over the indices of a sequence. It is particularly suitable for situations where you don't need to store the entire sequence in memory at once.

Memory Footprint

range() has a very small memory footprint because it only stores the start, stop, and step values. It calculates the numbers on demand, making it much more memory-efficient than creating a full list of numbers. For example, range(1000000000) takes up very little memory, whereas list(range(1000000000)) would likely crash your program due to memory limitations.

Alternatives

  • enumerate(): If you need both the index and the value when iterating over a sequence, enumerate() is a better choice.
  • List comprehensions: For creating lists based on a range of numbers with modifications, list comprehensions can be more concise.
  • NumPy's arange(): If you need to generate a sequence of floating-point numbers, or if you're working with numerical computations and need more advanced features, numpy.arange() from the NumPy library is a powerful alternative.

Pros

  • Memory-efficient, especially for large ranges.
  • Simple and easy to use.
  • Built-in, so no external libraries are required.

Cons

  • Only works with integers.
  • Less flexible than list comprehensions for creating complex sequences.
  • Generates numbers on demand, so accessing a specific element (e.g., range(10)[5] in versions before Python 3.9) can be less efficient than accessing an element in a list. This has been optimized in Python 3.9+ to be O(1).

FAQ

  • What is the difference between `range()` in Python 2 and Python 3?

    In Python 2, range() creates a list of numbers, while in Python 3, range() returns a range object (an iterable) that generates numbers on demand. Python 3's range() is more memory-efficient.

  • Can I use `range()` with negative numbers?

    Yes, you can use range() with negative numbers for both the start, stop, and step values. For example, range(-5, 0) will generate -5, -4, -3, -2, -1.

  • How can I create a list from a `range` object?

    You can convert a range object to a list using the list() constructor. For example: my_list = list(range(5))

  • Can the step value be negative?

    Yes, the step value can be negative. For example, range(5, 0, -1) generates 5, 4, 3, 2, 1.