# The following is a tricky example: # This is an example function that possibly raises `StopIteration`. # In some cases, this function may raise `StopIteration` in the first iteration. def raise_stop_iteration(param): if param == 10: raise StopIteration # Suppose this function will do some simple calculation return -param # Then when we use builtin-function `map` and for-loop: print('example 1'.center(30, '=')) for item in map(raise_stop_iteration, range(5)): print(item) print('end of example 1'.center(30, '=')) # It works well. The output of example 1 is 0 to -4. # But the following can be triky: print('example 2'.center(30, '=')) for item in map(raise_stop_iteration, range(10, 20)): print(item) print('end of example 2'.center(30, '=')) # The output of exapmle 2 is just nothing, # and no errors are reported, # because `map` simply let the exception spread upward when executing `raise_stop_iteration(10)`. # However, the exception type is StopIteration, so the for-loop catches it and breaks the loop, # assuming this is the end of the loop. # When the exception raised from buggy mapping function is exactly `StopIteration`, # for example, functions implemented with builtin-function `next`, # it can be confusing to find the real issue. # I think it might be better improved in this way: class my_map: def __init__(self, mapping_function, *iterators): self.mapping = mapping_function self.iterators = iterators def __iter__(self): for parameter_tuple in zip(*self.iterators): try: yield self.mapping(*parameter_tuple) except BaseException as e: raise RuntimeError(*e.args) from e # It works like the map in most cases: print('example 3'.center(30, '=')) for item in my_map(raise_stop_iteration, range(5)): print(item) print('end of example 3'.center(30, '=')) # And then, the crash of the buggy mapping function will be reported: print('example 4'.center(30, '=')) for item in my_map(raise_stop_iteration, range(10, 20)): print(item) print('end of example 4'.center(30, '='))