Write for loops over a list, a string, a dictionary and a range, and show the value the loop variable takes each time.
A Python for loop does not work with indexes at all. Instead, it asks the object for an iterator, and then it calls next on that iterator again and again until the iterator is empty.
for number in [10, 20, 30]:
print(number)
for letter in 'abc':
print(letter)
for key in {'a': 1, 'b': 2}:
print(key)
for index in range(3):
print(index)
The output is 10, 20, and 30 for the first loop. It is a, b, and c for the second one. It is a and b for the third loop, because a dictionary gives you its keys in the order they were added. It is 0, 1, and 2 for the last loop, because range(3) starts at zero and stops before the stop value.
Two details are worth pointing out here. Iterating a dictionary directly gives you the keys, so a very common mistake is to expect the values instead. When you want both halves of each pair, you use items() instead. And range(3) gives you 0, 1, and 2 because it starts at zero and stops before the number you gave it.
Underneath, the loop does the same thing as asking for an iterator with the two-argument form of iter and then calling next over and over. That is why any object with __iter__ and __next__ can be used in a for loop, and it is also why a for loop over a generator uses the values one at a time instead of building a list first.
The trap that catches people out is changing a list while you are looping over it. A list iterator keeps a position rather than a copy of the list, so removing an item shifts the later items down one place and the loop skips one of them. Appending to the list keeps the loop going for longer than you expected, because the iterator moves towards the current end of the list every time it runs.