Introducing Some Functional Features
First-class functions
Functional programming is often succinct and expressive. One way to achieve
this is by providing functions as arguments and return values for other functions.
We'll look at numerous examples of manipulating functions.
For this to work, functions must be first-class objects in the runtime environment.
In programming languages such as C, a function is not a runtime object. In Python,
however, functions are objects that are created (usually) by the def statements
and can be manipulated by other Python functions. We can also create a function
as a callable object or by assigning lambda to a variable.
Here's how a function definition creates an object with attributes:
def example(a, b, *kw):
... return ab
type(example)
<class 'function'>
example.code.co_varnames
('a', 'b', 'kw')
example.code.co_argcount
2
We've created an object, example, that is of class function(). This object has
numerous attributes. The code object associated with the function object has
attributes of its own. The implementation details aren't important. What is important
is that functions are first-class objects, and can be manipulated just like all other
objects. We previously displayed the values of two of the many attributes of a
function object.
Pure functions
To be expressive, a function used in a functional programming design will be free
from the confusion created by side effects. Using pure functions can also allow some
optimizations by changing evaluation order. The big win, however, stems from pure
functions being conceptually simpler and much easier to test.
To write a pure function in Python, we have to write local-only code. This means
we have to avoid the global statements. We need to look closely at any use of
nonlocal; while it is a side effect in another scope, it's confined to a nested function
definition. This is an easy standard to meet. Pure functions are a common feature of
Python programs.