
I think the discussion is sort of missing a very common use case, when a user calls func(iterator) and the function is expecting an iterable but not an iterator. The author of the called code might be thinking that the input is a list but that doen't mean the caller thinks that. Even worse is a case like this: def func(data_list): if VERBOSE: log(... [ ... for i in data_list ... ] ...) for i in data_list : do stuff with i The behavor of this code changes (significantly!) when VERBOSE is set. That's going to make debugging hard. [Yes, I know this can be safely written using itertools.tee. That doesn't mean that everyone will do that.] Here's a simple way to describe what the behavior could be (although obviously this doesn't work): def safer_iter_behavior(iterator): yield from iterator raise StopIteration raise RuntimeError That is, when you iterate the first time, it acts as expected, raising StopIteration when the list is exhausted. If you continue to iterate after the list is exhausted, it raises RuntimeError. In addition to the double iteration case above, it guards against other cases like: for x in iterator1: y = next(iterator2) do stuff when the iterator2 is unexpectedly shorter than iterator1. Of course, naively guarding against that by adding if len(iterator1) != len(iterator2): ... would be a bad idea and would also result in RuntimeError. --- Bruce