len() and range()¶
range() defines an iteration space; len() measures the size of a collection. Together they are among the most frequently used built-ins in Python.
Mental Model
len() asks "how big is this?" and range() asks "give me numbers from here to there." range() is lazy---it describes a sequence of integers without storing them all in memory. Together they let you measure collections and generate index sequences for iteration.
len()¶
len() returns the number of elements in a container.
```python numbers = [1, 2, 3, 4] print(len(numbers)) # 4
text = "Python" print(len(text)) # 6 ```
Works with any sized container: lists, tuples, strings, dictionaries, and sets.
range()¶
range() generates a sequence of integers. It is lazy — the numbers are produced on demand rather than stored all at once.
Three forms:
python
range(stop) # 0 up to (not including) stop
range(start, stop) # start up to (not including) stop
range(start, stop, step)# start up to stop, stepping by step
python
for i in range(5):
print(i) # 0 1 2 3 4
python
for i in range(2, 10, 2):
print(i) # 2 4 6 8
range() produces integers only. To iterate over a list by index, combine it with len():
python
fruits = ["apple", "banana", "cherry"]
for i in range(len(fruits)):
print(i, fruits[i])
Output:
text
0 apple
1 banana
2 cherry
In practice this pattern is rare — enumerate() is almost always clearer. See enumerate() and zip().
Key Ideas¶
len() measures a container; range() generates integers for iteration.
range() is lazy and memory-efficient — range(1_000_000) uses no more memory than range(5).
Avoid range(len(seq)) when you need both index and value — use enumerate() instead.
Practical Example¶
```python
Pagination: split items into pages of size 3¶
items = ["a", "b", "c", "d", "e", "f", "g"] page_size = 3
for i in range(0, len(items), page_size): page = items[i:i+page_size] print(page) ```
Notebook Examples¶
```python for i in range(10): print(i, end=" ")
print() print(i) # 9 ```
Exercises¶
Exercise 1.
range() is lazy -- it does not store all values in memory. Predict the output:
python
r = range(1_000_000)
print(type(r))
print(len(r))
print(r[999_999])
print(500_000 in r)
Why can range support len(), indexing, and in without storing all million numbers? What data structure does range use internally?
Solution to Exercise 1
Output:
text
<class 'range'>
1000000
999999
True
range stores only three values internally: start, stop, and step. It computes any requested value on the fly using arithmetic: r[i] = start + i * step. len(r) = (stop - start + step - 1) // step. x in r checks if x is within bounds and lands on a step.
This is why range(1_000_000) uses the same amount of memory as range(5) -- it never materializes the sequence. This is an example of a lazy object (as introduced in the overview) that supports random access through computation rather than storage.
Exercise 2.
len() works by calling the __len__ method on the object. Predict which calls succeed and which raise errors:
python
print(len([1, 2, 3]))
print(len("hello"))
print(len({1, 2, 3}))
print(len(42))
print(len(range(10)))
Why does len(42) fail? What does an object need to support len()?
Solution to Exercise 2
text
3
5
3
TypeError: object of type 'int' has no len()
10
len(42) raises TypeError because integers do not have a __len__ method. len() works by calling obj.__len__(), so an object supports len() if and only if its class defines __len__.
Lists, strings, sets, dicts, tuples, and ranges all define __len__. Integers, floats, booleans, and None do not, because they are not containers.
Exercise 3.
range() supports negative steps. Predict the output:
python
print(list(range(10, 0, -1)))
print(list(range(10, 0, -3)))
print(list(range(0, 10, -1)))
print(list(range(5, 5)))
Why does range(0, 10, -1) produce an empty list? What is the general rule for when a range is empty?
Solution to Exercise 3
Output:
text
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
[10, 7, 4, 1]
[]
[]
range(0, 10, -1) is empty because with a negative step, range counts downward, but start (0) is already less than stop (10). There is no way to count down from 0 to 10.
The general rule: a range is empty when:
step > 0andstart >= stop(counting up but already past the target)step < 0andstart <= stop(counting down but already past the target)
range(5, 5) is empty because start == stop -- there are no integers in the half-open interval [5, 5).