Functions, Iterators, and Generators
We'll write generator expressions that will perform the following tasks:
- Conversions
- Restructuring
- Complex calculations
We'll make a quick survey of many of the built-in Python collections, and how we
can work with collections while pursuing a functional paradigm. This might change
our approach to working with lists, dicts, and sets. Writing functional Python
encourages us to focus on tuples and immutable collections. In the next chapter,
we'll emphasize more functional ways to work with specific kinds of collections.
Writing pure functions
A pure function has no side effects: there are no global changes to variables. If we
avoid the global statement, we will almost meet this threshold. We also need to
avoid changing the state mutable objects. We'll look at a number of ways of ensuring
these two aspects of pure functions. A reference to a value in the Python global using
a free variable is something we can rework into a proper parameter. In most cases,
it's quite easy.
Here is an example where the usage of the global statement is explained:
def some_function(a, b, t):
return a+b*t+global_adjustment
We can refactor this function to make the global_adjustment variable into a proper
parameter. We would need to change each reference to this function, which might
have a large ripple effect through a complex application. A global reference will be
visible as a free variable in the body of a function. There will be neither a parameter
nor an assignment for this variable, making it reasonably clear that it's global.
There are many internal Python objects, which are stateful. Instances of the file
class, and all file-like objects, are examples of stateful objects in common use. We
observe that the most commonly used stateful objects in Python generally behave
as context managers. Not all developers make use of the available context managers
but many objects implement the required interface. In a few cases, stateful objects
don't completely implement the context manager interface; in these cases, there's
often a close() method. We can use the contextlib.closing() function to
provide these objects with the proper context manager interface.