Higher-order Functions
This will try to assemble a tuple of n items taken from an iterable. If there are any
items in the tuple, they are yielded as part of the resulting iterable. In principle, the
function then operates recursively on the remaining items from the original iterable.
As the recursion is relatively inefficient in Python, we've optimized it into an explicit
while loop.
We can use this function as follows:
group_by_iter(7, filter( lambda x: x%3==0 or x%5==0, range(100)))
This will group the results of applying a filter() function to an iterable created by
the range() function.
We can merge grouping and filtering into a single function that does both operations
in a single function body. The modification to group_by_iter() looks as follows:
def group_filter_iter(n, predicate, iterable):
data = filter(predicate, iterable)
row= tuple(next(data) for i in range(n))
while row:
yield row
row= tuple(next(data) for i in range(n))
This function applies the filter predicate function to the source iterable. As the filter
output is itself a non-strict iterable, the data variable isn't computed in advance; the
values for data are created as needed. The bulk of this function is identical to the
version shown above.
We can slightly simplify the context in which we use this function as follows:
group_filter_iter(7, lambda x: x%3==0 or x%5==0, range(1,100))
Here, we've applied the filter predicate and grouped the results in a single function
invocation. In the case of the filter() function, it's rarely a clear advantage to
apply the filter in conjunction with other processing. It seems as if a separate, visible
filter() function is more helpful than a combined function.
Writing generator functions
Many functions can be expressed neatly as generator expressions. Indeed, we've seen
that almost any kind of mapping or filtering can be done as a generator expression.
They can also be done with a built-in higher-order function such as map() or
filter() or as a generator function. When considering multiple statement generator
functions, we need to be cautious that we don't stray from the guiding principles of
functional programming: stateless function evaluation.