Functional Python Programming

(Wang) #1

Functions, Iterators, and Generators


We can assign functions to variables, pass functions as arguments, and return functions
as values. We can easily use these techniques to write higher-order functions.


Since functions are objects, Python already has many features required to be a
functional programming language.


Additionally, a callable object also helps us to create functions, which are first-class
objects. We can even consider the callable class definition as a higher-order function.
We do need to be judicious in how we use the init() method of a callable object;
we should avoid setting stateful class variables. One common application is to use an
init() method to create objects that fit the Strategy design pattern.


A class following the Strategy design pattern depends on another object to provide
an algorithm or parts of an algorithm. This allows us to inject algorithmic details at
runtime, rather than compiling the details into the class.


Here is an example of a callable object with an embedded Strategy object:


import collections
class Mersenne1(collections.Callable):
def init(self, algorithm):
self.pow2= algorithm
def call(self, arg):
return self.pow2(arg)-1


This class uses init() to save a reference to another function. We're not
creating any stateful instance variables.


The function given as a Strategy object must raise 2 to the given power. The three
candidate objects that we can plug into this class are as follows:


def shifty(b):
return 1 << b
def multy(b):
if b == 0: return 1
return 2multy(b-1)
def faster(b):
if b == 0: return 1
if b%2 == 1: return 2
faster(b-1)
t= faster(b//2)
return t*t


The shifty() function raises 2 to the desired power using a left shift of the bits.
The multy() function uses a naive recursive multiplication. The faster() function
uses a divide and conquer strategy that will perform log 2 ()b multiplications instead
of b multiplications.

Free download pdf