Consider the following example:
def foo(iterator):
return sum(iterator) / max(iterator)
Is it safe to reuse the same iterator twice?
Consider the following example:
def foo(iterator):
return sum(iterator) / max(iterator)
Is it safe to reuse the same iterator twice?
No, it is not safe. Iterators are not sequences. Here's what happens with that foo()
function using a generator, which is itself an iterator:
>>> foo(x for x in range(10))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in foo
ValueError: max() arg is an empty sequence
This is because the iterator is already at its end when after sum()
finished its job, so max()
is getting no additional items from it. In general, it is not possible to reset an iterator so that it can be cycled through again. In order for the foo()
function to properly support iterators, it must be rewritten so that the iterator is cycled through only once, for example by saving the items from iterator
into a temporary tuple
or list
:
def foo(iterator):
iterable = list(iterator)
return sum(iterable) / max(iterable)
or, if iterator
yields a large number of items, by carefully handling it using a for
loop:
def foo(iterator):
# allows iterables like lists or tuples to be passed as arguments
iterator = iter(iterator)
try:
max_ = next(iterator)
sum_ = max_
except StopIteration:
# iterator yields no items, return some default value
return 0.0
for element in iterator:
sum_ += element
max_ = max(max_, element)
return sum_ / max_
This will produce the proper result:
>>> foo(x for x in range(10))
5.0