Functional programming in python intro

Python at it’s heart is not a functional programming language. This is not a claim I’m making, but the language creator Guido has stated so himself. If you want to learn more about a functional programming language then my advice is to focus on a language that’s purely functional at its core like Haskell. I would also suggest reading why isn’t python very good for functional programming discussion on stack overflow.

Even though python is not a purely functional programming language it enables elements of functional programming, just like it does for object oriented programming. The elements that we’ll focus on in this tutorial are lambdas, map, filter, and reduce functionality.

Lambdas

To get a better idea of how lambdas work in python let’s first take a look at a simple function in python:

>>> def formula(x, y, z):
...     return (x + y) * z
... 
>>> formula(5, 5, 10)
100

The above function can be translated into the logical equivalent by using a lambda as shown below:

>>> formula = lambda x, y, z: (x + y) * z
>>> formula(5, 5, 10)
100

To learn more about lambdas checkout the lambda page on the python docs: https://docs.python.org/3/reference/expressions.html#lambda
The general syntax for a lambda in python is as follows:

lambda arguments: expressions 

As you can see from the above example a lambda is a reserved keyword in python, and that the colon symbol is used to separate the input from the output. Therefore, in the above example the lambda expression accepts parameters of x, y, and z, and then return (x + y) * z. Let’s take a look at another function in python:

>>> def factorial(n):
...     if n == 0:
...         return 1
...     return n * factorial(n-1)
... 
>>> factorial(5)
120

The above is a classic recursion problem that shows the problem of computing the factorial of a number. This can be rewritten using lambdas in python as follow:

>>> fact = lambda n : 1 if n == 0 else  n * fact(n-1) 
>>> fact(5)

Like in the first lambda example you have the input on the left hand portion of the colon, and then you have the output which is on the right hand portion of the colon. However, the right hand portion needs an if condition to terminate the recursive calls or else a RecursiveError will occur.

Here’s something to keep in mind when using lambdas in python. You can’t use loops as iteration is not a programming construct that’s supported in functional programming. Below is another python function:

>>> def fahrenheit_to_celsius(temp):
...     return (temp - 32) * 5/9
... 
>>> fahrenheit_to_celsius(32)
0.0
>>> fahrenheit_to_celsius(50)
10.0
>>> fahrenheit_to_celsius(73.2)
22.88888888888889

We can translate the above to a lambda by using the following:

>>> fahrenheit_to_celsius =  lambda temp : (temp - 32) * 5/9 
>>> fahrenheit_to_celsius(10)
-12.222222222222221
>>> fahrenheit_to_celsius(23.7)
-4.611111111111111
>>> fahrenheit_to_celsius(100)
37.77777777777778

Also,lambdas don’t have to be isolated from traditional functions in python as they can be used in conjunction with them. For example, look at the following code snippet:

>>> def formula(x, y, z):
...     return lambda a : a + (x * y * z)
... 

>>> a = formula(2, 3, 4)
>>> a(5)
29

When you call formula() the following happens:

a = formula(2, 3, 4)
→ a + 24 
Then the following is called:
>>> a(5) 
The following happens:
→ 5+ 24 = 29

The map() function

The map() function applies a function over an iterable. For example, say that you create a function and want to apply it to all of the elements in an iterable, how would you do this? Well, you can do something like the following:

>>> def f(x):
...         return x + x

>>> for y in range(10):
...         print(f(y), end=' ')
... 
0 2 4 6 8 10 12 14 16 18

However, this logic can be written in a style that emulates functional programming in python. If we use just a lambda we run into a shortcoming as shown below:

>>> f = lambda y : y + y 
>>> f(10)
20
>>> f(1, 2)
Traceback (most recent call last):
  File "", line 1, in 
TypeError: () takes 1 positional argument but 2 were given

Everything is ok if we enter in just one argument, but if we enter several then we will get an error. Therefore, we can use the builtin map() function in python. Below is the map() function details:

map(function, iterable, …)

As you can see from the map function details, it returns an iterator that applies a function to all of the items in the iterable.

>>> nums = [x for x in range(1, 10)]
>>> f = map(lambda y : y + y, nums)
>>> f

>>> list(f)
[2, 4, 6, 8, 10, 12, 14, 16, 18]

The update we made was to add the map function and the iterable to be passed. As you can see by using a lambda and the map() function we can reduce the code while still making it expressive. Instead of creating a separate function, writing a loop, and applying a function to it, we can create the function with a lambda, and then use the map() function to apply the lambda to all of the elements in an iterable. Also, keep in mind that above could be replicated by using a list comprehension as shown below:

>>> [x + x for x in range(1, 10)]
[2, 4, 6, 8, 10, 12, 14, 16, 18]

The Filter Function

The details of the filter function are listed below:

filter(function, iterable)

Let’s take a look at a simple function in python:

>>> def f(*x):
...     truth = []
...     for y in x:
...         if y >= 5:
...             truth.append(y)
...         else:
...             pass
...     return truth
... 
>>> f(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
[5, 6, 7, 8, 9]

As you can see, f(*x) accepts an arbitrary amount of numbers and then returns only the numbers that’s greater than or equal to 5. This could be re-written as a list comprehension as follows:

>>> x = [x for x in range(10) if x >= 5]
>>> x
[5, 6, 7, 8, 9]

Finally, this can be re-written using a lambda and filter function.

>>> x = filter(lambda x  : x >= 5, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> list(x)
[5, 6, 7, 8, 9]

You’ll need to convert the expression to a list or else you’ll be left with the filter object which is not as interesting:

>>> x

The Reduce Function

Say that you want to re-write the sum() function in the python docs. You can do this by using iteration like in the following example:

>>> def summation(*args):
...     value = 0
...     for x in args:
...         value += x
...     return value
... 
>>> summation(5, 10, 15, 20)
50

However, you can replicate this using a functional programming approach in python by doing the following:

>>> from functools import reduce
>>> x = reduce(lambda x, y : x + y,  [5, 10, 15, 20])
>>> x
50

If you’re using python 3.x then the reduce() function has been moved to the functools module. You can read up more about it in The fate of reduce() in Python 3000 by python creator Guido van van Rossum:

============================================================================ Want to learn how to use Python's most popular IDE Pycharm? In the free pdf guide "Getting the Hang of PyCharm" you'll learn all of the amazing features in PyCharm along with how to get started with data science. Subscribe to the Purcell Consult newsletter and get started A.S.A.P.