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, 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
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:
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
but it does have functions that
can replace the behavior of the loops.
Below is a classic example of iterative loops in Python:
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
map, a method that applies
a custom function to all the elements of a list.
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
which creates a new list with the elements
that return true when certain function
is applied to a list, for 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.
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
a module designed to make efficient loops
in iterable objects, based on languages such as
In fact, you already know some functions
of this module like
but now they come with the whole family and on steroids.
Some of the representative methods of this library are:
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
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
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.
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
a module with higher-level functions,
created with the specific purpose of making Python more functional.
This module, like
is in the core of Python.
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.
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.