Road to Functional PythonFunctional coding in Python
Probably there is nothing better for the spirit than having a hobby that we are passionate about, that makes us feel in love all the time and makes us want to return to it. Better, the results obtained while practicing your hobby, without any intention, becomes a global phenomenon, used by large and small companies becoming in the source of income for many. This is how Python came about, a project initially as a hobby, but over the years has earned a place among the most widely used languages, not only because is easy to use but for its versatility. Python has been able to adapt to the frenetic changes in technology and has been a strong contender in many fields. Today it wants to change again, it wants to evolve before the same evolution arrives. Today it wants to be functional!
Before putting on shoes
Before starting, I must warn you that this trip is not for beginners. You will not be able to face functional Python and survive if you do not know the basic Python. If this is your case, do not feel bad, you can’t walk if you don’t even know how to stand, so go and scrape your knees in a Python playground. Also, get some context by reading Why we go functional?, which is the prequel of this article. When you think you’re ready, come back to the road, always be waiting for you.
Prepare your backpack
Of course we need supplies for the road. But surprise! If you already
have Python then you are ready to start walking. One of the most
important characteristics of Python is the multiparadigm coding, meaning
that it supports several programing paradigms in its code. Paradigms can
be the object-oriented, procedural, functional, among others. There are
also libraries with functional features such as
functools that are
included in the basic installation.
First baby steps
One of the main characteristics of the functional paradigm is the possibility to have methods that receive or return code. This is difficult to understand in some languages but in Python things are easier, for example:
First approximation for basic operations in functional Python.
def calc (f, x, y): return f(x, y) def subtract (x, y): return x - y def mult (x, y): return x * y calc(subtract, 10, 3) # 7 calc(mult, 2, 4) # 8
Perhaps the hardest thing to understand in the functional paradigm is
that there are no iterative cycles, so if you have ever programmed in
some object-oriented language you maybe think that without iterative
cycles you can’t do much or you can’t generate short and clean code. You
are right, partially. The functional paradigm doesn’t have something
for or a
while loop, but it does have functions that can
replace the behavior of the loops.
Below is a classic example of iterative loops in Python:
Increment in list elements example.
integer_list = [7, 8, 9] def increment (x): return x + 1 def increment_in_list (list): result =  for integer in list: result.append(increment(integer)) return result increment_in_list(integer_list) # [8, 9, 10]
If we want to do that in a functional way then we can use
method that applies a custom function to all the elements of a list.
Increment in list elements with map.
integer_list = [7, 8, 9] def increment (x): return x + 1 map(increment, integer_list) # [8, 9, 10]
Another function that allows iterative operations is
creates a new list with the elements that return true when certain
function is applied to a list, for example:
Filter method example.
integer_list = [7, 8, 9] def greater_than (x, y): return True if x > y else False filter(lambda x: greater_than(x, 7), integer_list) # [8, 9]
These are really useful and simple functions to start coding but sadly also have some limitations, for example, functions to apply to the lists cannot have more than one input argument. This is not a problem. Soon we will study even more powerful functional methods.
Take a break
You’ve come a long way, congratulations! You have almost all the knowledge to enter the big leagues, you just have to learn something else: Lambda expressions, described as one line functions (anonymous functions in other languages). Below we rewrite the increment in list elements example using lambda expressions.
Increment in list elements with lambda expression.
integer_list = [7, 8, 9] map(lambda x: x + 1,integer_list) # [8, 9, 10]
Run Forrest, Run!
We are now next to world-class athletes and we can learn a lot from
them. One of the most prominent is
module designed to make efficient loops in iterable objects, based on
languages such as
SML. In fact, you already know some
functions of this module like
filter, but now they come with
the whole family and on steroids.
Some of the representative methods of this library are:
Example of some itertools methods.
import itertools lowercases = ['a','b','c'] uppercases = ['A','B','C'] number_as_string = '1111222334' """ Chain, allows you to concatenate iterative structures """ list(itertools.chain(uppercases, lowercases)) # ['A', 'B', 'C', 'a', 'b', 'c'] """ Permutations, returns the permutations of n elements in an iterable structures """ list(itertools.Permutations(uppercases, 2)) # [('A','B'),('A','C'),('B','A'),('B','C'),('C','A'),('C','B')] """ Groupby, group up elements of a data structure based on a condition or rule """ [list(g) for k, g in itertools.groupby(number_as_string)] # [['1', '1', '1', '1'], ['2', '2', '2'], ['3', '3'], ['4']] """ Repeat, returns an element as many times as specified """ list(itertools.repeat('A',6)) # ['A', 'A', 'A', 'A', 'A', 'A'] """ Islice, returns n elements of an iterative structure """ list(itertools.islice(number_as_string,5)) # ['1', '1', '1', '1', '2']
Not all functional approaches in Python are manifested as libraries,
there are also functional features that are achieved by just writing our
code in a certain way. One of these ways is
currying, which is defined
as the transformation of a function that receives several input
parameters to a sequence of functions that receives a single parameter.
Why would we do this? Well, this is linked with
laziness and functions
that create functions, currying allows a partially execution of a
function, making runtime more efficient by avoiding the calculation of
every operation from the beginning.
Example of currying in Python.
def curried_product (a): def product(b): return a * b return product curried_product(2) # function... curried_product(2)(3) # 6 mult = curried_product(3) # function... mult(4) # 12
Learning to fly
Now we’ll learn something more sophisticated and exclusive than all of
the above. I will teach you
module with higher-level functions, created with the specific purpose of
making Python more functional. This module, like
itertools, is in
the core of Python.
Example of some functools methods.
import functools """ Partial, generates a function by partially executing an input function """ def multiply(a,b): return a * b partial_multiply = partial(multiply,6) print(partial_multiply(2)) # 12 """ Reduce, applies a function of 2 input arguments to a data structure """ functools.reduce(lambda x, y: x + y, [1, 2, 3, 4, 5]) # 15 """ Update_wrapper, copy attributes from one function to another """ from functools import update_wrapper def foo(): """This is a foo attribute""" pass def bar(): pass update_wrapper(bar, foo) bar.__doc__ # 'This is a foo attribute'
Limit is in your mind
Here we are, the end of our trip together. But the road does not end at all. We have only taught you how to hit the road but you are the one who decides where to go. Python is a powerful language driven by thousands of people around the world who use their free time to create and improve code for all of us to use. That’s why, daily, the limitations of Python are disappearing, leaving the limits only in our mind.
Figure 1. What some developers think about multiparadigm coding.
Functional Python is about doing things in the most optimal way possible. The first thing we must change is our way of thinking. Humans are reluctant to change, we are afraid of the new but from time to time there are some specimens who open their minds and take risks, those are who drive humanity to a superior level. Why not take the risk using functional Python then? We actually took the risk with functional Python and the result was one of our most awesome and acclaimed products: Asserts (though, we not longer offer this product).
Python is a very useful language that collects the best of different worlds. Due to its multiparadigm nature, it’s not a problem if we experiment with different paradigms in the same code, and for that reason we should not limit ourselves to just one. Each paradigm has advantages and disadvantages.
Possibly your code in Python is object oriented and that’s fine, it’s a great opportunity to analyze your code and see what you can transform or create with any of the tools that you have seen here or that you can learn by yourself. I already told you, the limit is in your mind. Start refactoring small components to be functional, this will give you more confidence and change a bit the way you see the world and the way you solve problems. Nothing more grateful than a good code. A code that over the years continues efficient and useful, that doesn’t lose validity. Our advice is to take a deep breath and get on the road to functional Python.