"""Module for demonstrating generator execution.""" def take(count, iterable): """Take itemsm from teh front of an iterable. Args: count: The maximum number of items to retrieve. iterable: The source series. Yields: At most 'count' items from the 'iterable'. """ # keep track of how many elements have been yielded so far counter = 0 for item in iterable: if counter == count: # terminate stream of yielded values (raises StopIteration exception) return counter += 1 print('.....take yield ' + str(item)) yield item def distinct(iterable): """Return unique items by eliminating duplicates. Args: iterable: The source series. Yields: Unique elements in order from 'iterable'. """ # Use a set to keep track of what items we've already seen seen = set() for item in iterable: if item in seen: # Finish current iteration of loop and begin next iteration immediately continue print('.....distinct yield ' + str(item)) yield item # When generator resumes, complete the work of the previous call by remembering what was seen # this works because 'item' is not re-assigned until we get back to for statement seen.add(item) def run_distinct(): print('=== DISTINCT ===') items = [5, 7, 7, 6, 5, 5] for item in distinct(items): print(item) def run_take(): print('=== TAKE ===') # create a source list for the generator function items = [2, 4, 6, 8, 10] for item in take(3, items): print(item) def run_pipeline(): print('=== PIPELINE ===') items = [3, 6, 6, 2, 1, 1] for item in take(3, distinct(items)): print(item) if __name__ == '__main__': run_take() run_distinct() run_pipeline()