Chapter 5
The benefit of using a Callable to create a composite function gives us slightly
simpler syntax when the resulting composite function is used. When we start
working with iterable mappings or reductions, we have to be aware of how
and why we introduce stateful objects.
We'll return to our sum_filter_f() composite function shown above. Here is a
version built from a Callable class definition:
from collections.abc import Callable
class Sum_Filter(Callable):
slots = ["filter", "function"]
def init(self, filter, function):
self.filter= filter
self.function= function
def call(self, iterable):
return sum(self.function(x) for x in iterable if
self.filter(x))
We've imported the abstract superclass Callable and used this as the basis for our
class. We've defined precisely two slots in this object; this puts a few constraints on
our ability to use the function as a stateful object. It doesn't prevent all modifications
to the resulting object, but it limits us to just two attributes. Attempting to add
attributes results in an exception.
The initialization method, init(), stows the two function names, filter and
function, in the object's instance variables. The call() method returns a value
based on a generator expression that uses the two internal function definitions.
The self.filter() function is used to pass or reject items. The self.function()
function is used to transform objects that are passed by the filter() function.
An instance of this class is a function that has two strategy functions built into it.
We create an instance as follows:
count_not_none = Sum_Filter(lambda x: x is not None, lambda x: 1)
We've built a function named count_not_none() that counts the non-None values
in a sequence. It does this by using a lambda to pass non-None values and a function
that uses a constant 1 instead of the actual values present.