006 - Pure, Functional, Financial Python Katas

In Python for Finance, the author gives an example of three ways in chapter 1 to do a large mathematical calculation using different Python libraries.

The moral of the story, in Python, there are many ways to skin a cat, and it is important to experiment.

We are experimenting the hell out of this pure lambda or functional programming style right now, so rewrite the following examples with lambdas only.

loops = 25000000  
from math import *  
a = range(1,loops)  
def f(x):  
  return 3 * log(x) + cos(x) ** 2
def r():  
  [f(x) for x in a]

Using %timeit, this takes 12 seconds on my laptop, versus 15 seconds on the original author's laptop. My lambda implementation takes 13 seconds.

Let's use the Numpy library now.

import numpy as np  
np_a = np.arange(1,25000000)  
def np_r():  
  return 3 * np.log(np_a) + np.cos(np_a) ** 2

This version takes 2 seconds and my lambda spin on this, also takes the same time.

import numexpr as ne  
f = '3 * log(a) + cos(a) ** 2'  
def ne_r():  
  return ne.evaluate(f)

The number expression library has similar results, hitting about 2 seconds. Note that the a stays as a variable, as the expression string cannot inter-operate with lambdas.

Apart from light exercise, what have we learned?

Lambdas aren't terribly slow, in fact they are more or less comparable.

Also, as we saw yesterday, using lambdas means that our functions are mostly pure, which also means our code is memoisable.

Memoisation is a way of saving inputs and outputs in a table, every time we call the function we check whether we already have the result in the table or cache rather than computing the function repeatedly. This happens to coincide with the definition of pure functions.

Perhaps lambdas will really shine when memoised, because we can ensure less funny business with mutable global state interfering with our calculations, meaning we never have to worry whether our cache is out of date.

We have found a new way to skin cats.

More to come.