The following code:
a = list(range(10))
remove = False
for b in a:
if remove:
a.remove(b)
remove = not remove
print(a)
Outp
As Mikola explained, the actual result you observe is caused by the fact that deleting an entry from the list shifts the whole list over by one spot causing you to miss elements.
But the more interesting question, to my mind, is why python doesn't elect to produce an error message when this happens. It does produce such an error message if you try to modify a dictionary. I think there are two reasons for that.
Dict are complex internally, whereas lists are not. Lists are basically just arrays. A dict has to detect when its modified while being iterated over so as to avoid crashing when the internal structure of the dict changes. A list can get away without doing that check because it just makes sure that its current index is still in range.
Historically, (I'm not sure about now), python lists were iterated over by using the [] operator. Python would evaluate list[0], list[1], list[2] until it got an IndexError. In that case, python wasn't track the size of the list before it began so it had no method of detecting that the size of list had been changed.