| [ Web Proxy ] |
| Viewing: https://www.pythonbyexample.dev/examples/iterator-vs-iterable | [Back] [Original] |
Iteration
A list is iterable. Each for loop or list() call asks the list for a fresh iterator under the hood, so the same data can be traversed many times.
Source
names = ["Ada", "Grace"]
print(list(names))
print(list(names))Output
['Ada', 'Grace']
['Ada', 'Grace']An iterator is one-pass. Calling iter() returns a position-tracking object; once it has been exhausted, it stays exhausted.
Source
stream = iter(names)
print(list(stream))
print(list(stream))Output
['Ada', 'Grace']
[]Calling iter() on an iterable returns a brand-new iterator each time. Calling iter() on an iterator returns the same object that is the rule that lets a for loop accept either kind.
Source
first = iter(names)
second = iter(names)
print(first is second)
print(iter(first) is first)Output
False
TrueThe distinction shows up at API boundaries. A function that loops over its argument twice works for an iterable but silently produces wrong answers for an iterator, because the second pass finds the iterator already exhausted. Materialize once at the boundary when both passes matter.
Source
def total_and_count(numbers):
total = sum(numbers)
count = sum(1 for _ in numbers)
return total, count
def values():
yield from [10, 9, 8]
print(total_and_count([10, 9, 8]))
print(total_and_count(values()))
def total_and_count_safe(numbers):
items = list(numbers)
return sum(items), len(items)
print(total_and_count_safe(values()))Output
(27, 3)
(27, 0)
(27, 3)Notes
iter() is called on it; an iterator produces values until it is exhausted.iter(iterable) returns a fresh iterator; iter(iterator) returns the same iterator.['Ada', 'Grace']
['Ada', 'Grace']
['Ada', 'Grace']
[]
False
True
(27, 3)
(27, 0)
(27, 3)
Execution time appears here after you run the example.
| Web Proxy Viewer | New URL | Original Page |