You number three files starting at 1, but the last file disappears from the output. The loop finishes without an error, and the first two lines look fine. The second argument to range() is the boundary where iteration stops, not the final value it produces.
Why doesn't range(1, 4) produce 4?
range(start, stop) begins at start and ends before stop.
print(list(range(1, 4))) # [1, 2, 3]
print(list(range(4))) # [0, 1, 2, 3]The stop value is excluded. To include 4 when starting at 1, use range(1, 5). With one argument, as in range(4), the default start is 0.
The diagram marks 4 as the exclusive stop boundary. range(4) uses the same boundary but starts at 0.
The missing file when numbering a list
Consider a three-file list. len(files) is 3, but this loop does not include its stop value of 3:
files = ["app.log", "db.log", "web.log"]
for number in range(1, len(files)):
print(number, files[number - 1])1 app.log
2 db.logweb.log is still in the list. The loop simply produces only [1, 2]. To number all three files, add 1 to the exclusive stop boundary:
for number in range(1, len(files) + 1):
print(number, files[number - 1])1 app.log
2 db.log
3 web.logThe number - 1 matters too. Display numbers start at 1, while list indexes start at 0. Using files[number] would skip the first file and eventually raise IndexError.
Is enumerate() simpler for display numbers?
If you only want to number each file starting at 1, avoid manual index arithmetic:
for number, filename in enumerate(files, start=1):
print(number, filename)The output matches the corrected loop. enumerate() gives you a display number and the corresponding item, so there is no len(files) + 1 or number - 1 to coordinate. If you need the index itself, range(len(files)) produces 0, 1, 2, which you can use directly as files[index].
Also check the boundary cases: an empty list and a one-item list.
for count in (0, 1, 3):
numbers = list(range(1, count + 1))
assert len(numbers) == countThis checks that the loop produces the intended number of values. If the contents matter, also verify that the final item was processed.
Key takeaways
range(start, stop) excludes stop. Use range(1, N + 1) for numbers from 1 through N, or range(N) for zero-based list indexes. To attach display numbers to items, enumerate(items, start=1) is usually clearer and leaves less room for an off-by-one error.

