How to use range() in Python

The range() function in Python creates sequences of numbers efficiently. This built-in function helps you generate numeric sequences for loops, list creation, and iteration tasks, making it essential for Python programming fundamentals.

This guide covers practical techniques and real-world applications for mastering range(), with code examples created using Claude, an AI assistant built by Anthropic.

Basic usage of range()

for i in range(5):
    print(i, end=' ')
0 1 2 3 4

The example demonstrates range()'s most common usage pattern: generating a sequence from 0 to n-1. When you provide a single argument like range(5), Python creates an arithmetic progression starting at 0 and stopping just before 5.

This behavior makes range() particularly useful for array indexing and counting iterations. The function generates these numbers on-demand rather than storing them all in memory at once, making it memory-efficient for large sequences.

  • The output shows space-separated numbers (0 through 4) because of the end=' ' parameter in print()
  • Without specifying a start value, range() automatically begins at 0—matching Python's zero-based indexing convention

Alternative ways to use range()

Beyond its basic zero-to-n functionality, range() offers flexible parameters and type conversion options that unlock more sophisticated sequence generation capabilities.

Using range() with start, stop, and step parameters

for i in range(2, 10, 2):
    print(i, end=' ')
2 4 6 8

The range() function accepts three parameters that give you precise control over sequence generation. In this example, range(2, 10, 2) creates a sequence starting at 2, stopping before 10, and incrementing by steps of 2.

  • The first parameter (2) sets the starting point
  • The second parameter (10) defines where to stop—the sequence won't include this number
  • The third parameter (2) determines the step size between each number in the sequence

This explains why the output shows 2, 4, 6, and 8. The sequence begins at 2 and adds 2 each time until it reaches 8. It stops before hitting 10 because the stop parameter is exclusive.

Using range() with negative step

for i in range(10, 0, -1):
    print(i, end=' ')
10 9 8 7 6 5 4 3 2 1

The negative step parameter in range() creates a countdown sequence, making numbers decrease instead of increase. When you specify range(10, 0, -1), Python starts at 10 and counts backward until it reaches 1.

  • The first parameter (10) marks the starting point
  • Zero acts as the stopping point but isn't included in the output
  • The step value of -1 tells Python to subtract 1 in each iteration

This pattern proves especially useful when you need to process items in reverse order or implement countdown functionality in your programs. The sequence maintains Python's exclusive upper bound principle even when counting backward.

Converting range() to other data types

numbers_list = list(range(1, 6))
numbers_tuple = tuple(range(1, 6))
numbers_set = set(range(1, 6))
print(numbers_list, numbers_tuple, numbers_set)
[1, 2, 3, 4, 5] (1, 2, 3, 4, 5) {1, 2, 3, 4, 5}

Python's range() output transforms easily into other data structures. The example demonstrates converting a sequence into three common Python data types: lists, tuples, and sets.

  • Lists (list(range(1, 6))) create a mutable sequence you can modify later
  • Tuples (tuple(range(1, 6))) produce an immutable sequence that can't be changed
  • Sets (set(range(1, 6))) generate an unordered collection of unique elements

Each conversion function wraps around range() to create its respective data structure. The output shows identical values presented in different notation: square brackets for lists, parentheses for tuples, and curly braces for sets.

Advanced techniques with range()

Building on these foundational concepts, range() unlocks even more powerful capabilities when combined with Python's list comprehensions, enumerate() function, and memory-efficient design patterns.

Using range() in list comprehensions

squares = [x**2 for x in range(1, 6)]
print(squares)

cubes = [x**3 for x in range(1, 6)]
print(cubes)
[1, 4, 9, 16, 25]
[1, 8, 27, 64, 125]

List comprehensions combine range() with mathematical operations to create sequences efficiently. The example generates squares and cubes of numbers 1 through 5 in a single line of code. This approach proves more concise than traditional loops while maintaining readability.

  • The expression x**2 calculates squares by raising each number to the power of 2
  • Similarly, x**3 computes cubes using the power of 3
  • The range(1, 6) function provides the input numbers 1 through 5

The output shows how Python evaluates these expressions for each number in the sequence. The first list contains squares: 1, 4, 9, 16, and 25. The second list shows cubes: 1, 8, 27, 64, and 125.

Using range() with enumerate()

fruits = ["apple", "banana", "cherry"]
for index, fruit in enumerate(fruits, start=1):
    print(f"Fruit {index}: {fruit}")
Fruit 1: apple
Fruit 2: banana
Fruit 3: cherry

The enumerate() function pairs perfectly with range() to track both position and value when working with sequences. The start=1 parameter shifts the index counting from Python's default zero-based system to begin at 1 instead.

  • Each iteration unpacks two values: index captures the current position and fruit holds the item value
  • The f-string syntax (f"Fruit {index}: {fruit}") creates readable output by embedding these values directly in the text
  • This pattern works efficiently with any iterable object. You'll often use it when you need both the position and value of items in a sequence

While a basic range() loop could achieve similar results, enumerate() provides a more elegant solution that reduces code complexity and improves readability.

Memory efficiency of range()

large_range = range(1, 1000000)
size_in_bytes = large_range.__sizeof__()
print(f"Size: {size_in_bytes} bytes")
print(f"First: {large_range[0]}, Last: {large_range[-1]}")
Size: 48 bytes
First: 1, Last: 999999

The range() function demonstrates remarkable memory efficiency by storing only the start, stop, and step values instead of the entire sequence. This example creates a range of nearly one million numbers but consumes just 48 bytes of memory.

  • Python generates values on demand rather than storing the full sequence in memory
  • The __sizeof__() method reveals the minimal memory footprint
  • You can still access any value in the sequence instantly using index notation like large_range[0]

This memory-efficient design makes range() ideal for working with large sequences. You get the benefits of a full sequence without the memory overhead that would come from storing every number.

Using range() for batch processing data

The range() function enables efficient batch processing by dividing large datasets into smaller, manageable chunks that you can process sequentially without overwhelming system memory.

data = list(range(1, 21))  # Sample data with 20 items
batch_size = 5

for i in range(0, len(data), batch_size):
    batch = data[i:i+batch_size]
    print(f"Processing batch {i//batch_size + 1}: {batch}")

This code demonstrates a practical way to process a list in smaller chunks. The list(range(1, 21)) creates a list of numbers from 1 to 20. Setting batch_size = 5 determines how many items to process at once.

The loop uses range() with three arguments to iterate through the data in steps of 5. Inside the loop, list slicing data[i:i+batch_size] extracts each batch. The expression i//batch_size + 1 calculates the current batch number.

  • Each iteration processes exactly 5 items
  • The final batch might contain fewer items if the total isn't divisible by the batch size
  • This approach helps manage memory usage when working with large datasets

Creating a simple coordinate grid with range()

The range() function enables you to generate coordinate systems by nesting two loops that iterate through x and y values, creating a foundation for grid-based visualizations and spatial data structures.

grid_size = 3
for y in range(grid_size):
    for x in range(grid_size):
        coordinate = (x, y)
        print(f"{coordinate}", end=" ")
    print()  # New line after each row

This code generates a 3x3 grid of coordinates using nested range() loops. The outer loop controls the y-axis (rows), while the inner loop manages the x-axis (columns). Each iteration creates a tuple coordinate containing the current (x,y) position.

  • The end=" " parameter in print() places coordinates side by side
  • The final print() creates line breaks between rows

When executed, this code displays coordinates in a structured grid format, making it useful for tasks like game boards, matrices, or pixel mapping. The nested loop structure ensures we visit every possible position in the grid systematically.

Common errors and challenges

Understanding these common pitfalls with range() helps you write more reliable Python code and avoid subtle bugs that can affect your program's behavior.

Forgetting that range() is exclusive of the end value

A common mistake when using range() occurs when programmers expect the sequence to include the stop value. The function actually generates numbers up to but not including that final number. This behavior often leads to off-by-one errors in loops and calculations.

for i in range(1, 10):
    print(i, end=' ')

The code prints numbers 1 through 9 but excludes 10. Many developers expect to see 10 in the output since it's specified as the stop value in range(1, 10). Let's examine the corrected version below.

for i in range(1, 11):
    print(i, end=' ')

To include the final number in your sequence, increment the stop value by 1. The corrected code uses range(1, 11) to print numbers 1 through 10. This adjustment compensates for range()'s exclusive upper bound behavior.

  • Watch for this issue when converting between zero and one-based counting systems
  • Double check your stop values when working with array indices or counting specific quantities
  • Remember that range(n) always generates n numbers starting from zero

This pattern appears frequently in data processing and loop control. Pay special attention when implementing pagination or working with mathematical sequences that need to include their endpoint.

Using non-integer arguments with range()

The range() function only accepts integer arguments. Attempting to use floating-point numbers or decimal values will raise a TypeError. This limitation ensures precise sequence generation and prevents unexpected behavior in loops.

for i in range(0, 5.5):
    print(i, end=' ')

The code attempts to use a decimal number (5.5) as an argument for range(), which only processes whole numbers. Python raises a TypeError because it can't create a sequence with fractional steps. The corrected version below demonstrates the proper approach.

for i in range(0, int(5.5)):
    print(i, end=' ')

Converting decimal numbers to integers with int() resolves the TypeError that occurs when using floating-point values in range(). The function truncates decimals by removing everything after the decimal point. This solution works well when you need to generate sequences based on calculated or user-provided decimal values.

  • Watch for this error when working with mathematical calculations that produce decimals
  • Consider rounding with round() instead of int() if you need different decimal handling behavior
  • Remember that range() requires whole numbers to maintain precise sequence generation

Off-by-one errors when using range() with indices

Off-by-one errors frequently occur when developers miscalculate array boundaries while using range() with list indices. The subtraction operator len(items) - 1 in loops can accidentally exclude the last element from processing. This common mistake appears in the code below.

items = ["apple", "banana", "cherry", "date", "elderberry"]
for i in range(len(items) - 1):
    print(items[i])

The range(len(items) - 1) expression stops the loop one item too early, preventing the code from processing the final element "elderberry". The corrected version below demonstrates the proper way to iterate through the entire list.

items = ["apple", "banana", "cherry", "date", "elderberry"]
for i in range(len(items)):
    print(items[i])

Using range(len(items)) correctly iterates through all list indices from 0 to the last valid index. This approach ensures you process every element in the list without accidentally skipping the final item.

  • Watch for this error when processing lists sequentially or comparing adjacent elements
  • The pattern appears frequently in algorithms that need to access list items by their position
  • Consider using enumerate() as a cleaner alternative when you need both indices and values

Remember that Python's zero-based indexing means the last valid index is always len(items) - 1. However, range() automatically handles this by stopping before its end parameter.

FAQs

What is the basic syntax for creating a range() in Python?

Python's range() function creates a sequence of numbers using up to three parameters. The basic syntax follows range(start, stop, step) where only stop is required. The sequence begins at start (defaults to 0), continues until it reaches stop (but doesn't include it), and moves in increments of step (defaults to 1).

  • For counting 0 to 4: range(5)
  • For counting 2 to 5: range(2, 6)
  • For even numbers 0 to 8: range(0, 10, 2)

How do you create a range that starts from a number other than zero?

The range() function accepts up to three arguments: start, stop, and step. To begin from a specific number, provide it as the first argument. For example, range(5, 10) creates a sequence from 5 to 9.

Python excludes the stop value from the range because this behavior enables cleaner loops and better matches how we typically work with sequences—starting from zero-based indexing makes array operations more intuitive.

What happens when you use a negative step value in range()?

A negative step in range() makes Python count backwards, decrementing instead of incrementing. When you specify a negative step value like range(10, 0, -2), Python starts at the first number and counts down by the absolute value of the step until reaching the second number.

This enables powerful reverse iteration patterns. The sequence must flow logically—the start value needs to be larger than the stop value for negative steps to work. If the sequence can't flow as specified, range() will return an empty sequence.

Can you convert a range() object directly to a list?

Yes, you can convert a range() object directly to a list using the list() function. Python's range() creates an immutable sequence object that generates numbers on demand rather than storing them all in memory. Converting it to a list materializes all values at once.

This approach works because range() objects implement Python's iterator protocol. The list() constructor iterates through the range() sequence and builds a list containing all generated values.

Why doesn't range() include the stop value in the sequence?

The range() function follows a common programming pattern called "half-open intervals" where the start value is included but the stop value isn't. This design makes it easier to work with sequences that start at index 0 and helps avoid off-by-one errors when dealing with list lengths.

Consider a list with 5 items. Using range(0, 5) generates exactly 5 numbers—perfect for iteration. This approach also makes it simple to create adjacent ranges without overlap: range(0, 5) and range(5, 10) flow seamlessly together.

🏠