26.Iterators & Generators
Comprehensive Explanations
Iterators and generators are powerful tools in Python for handling sequences of data. An iterator is an object that contains a countable number of values and can be iterated upon. Generators are a simpler way to create iterators using functions and the ‘yield’ statement. They allow for lazy evaluation, meaning values are generated on the fly and not stored in memory.
Syntax and Multiple Examples
Creating an Iterator:
class MyIterator:
def __init__(self, max):
self.max = max
self.n = 0
def __iter__(self):
return self
def __next__(self):
if self.n < self.max:
result = self.n
self.n += 1
return result
else:
raise StopIteration
for i in MyIterator(5):
print(i)
Creating a Generator:
def my_generator(max):
n = 0
while n < max:
yield n
n += 1
for i in my_generator(5):
print(i)
Use Cases
– Reading large files line by line
– Streaming data from APIs
– Efficient looping over large datasets
– Implementing pipelines and coroutines
Differences Between Iterators and Generators
– Iterators require a class with __iter__() and __next__() methods
– Generators use functions and the ‘yield’ keyword
– Generators are more concise and memory-efficient
– Iterators provide more control and customization
Best Practices
– Use generators for large datasets to save memory
– Handle StopIteration properly in custom iterators
– Prefer generator expressions over list comprehensions for large data
– Avoid side effects in generator functions
Performance Considerations
Generators are generally more memory-efficient than iterators because they yield items one at a time. This makes them ideal for processing large data streams. However, iterators can be more flexible and customizable for complex iteration logic.