Does using the `iter' function consume a generator?

Viewed 74

For example, if I do something like the following:

def test():
    yield from range(100)
testing = test()
iter(testing)

If the iter function returns an iterator, but the result of the function call isn't assigned to a variable, why does running print(list(testing)) or similar return all the values? I thought converting a generator would consume the items inside.

2 Answers

Short answer

No, the iter() function does not consume an iterator; instead, it returns the iterator unchanged.

Annotated code

Here's what all the objects are called and what they are doing:

def test():                  # generator creation function
    yield from range(100)

testing = test()             # generator/iterator object

t2 = iter(testing)           # t2 and testing are identical

list(testing)                # runs the iterator to exhaustion

list(testing)                # this time you get an empty list

Explained

A generator object is a kind of iterator. They only run forward and run once. Calling next(it) retrieves a value and advances the iterator. Calling iter(it) returns the same iterator unchanged. To make a fresh new iterator, just call the generator creation function again: testing2 = test().

An iterable is something with a __iter__ method. An iterator is something with a __next__ method. The job of the iter function is to call the __iter__ method to get an iterable. These could all be the same, or different objects, depending on how they are implemented. Notably, the iterator does not consume the iterable. Although an iterable may return a different iterator object (for instance a list returns a list_iterator object), almost all iterators just return themselves. that way you don't have to check whether you already have an iterator when doing an iteration.

Related