Road to Functional Python

Functional coding in Python

Blog Road to Functional Python

| 6 min read

Contact us

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 programming paradigms in its code. Paradigms can be the object-oriented, procedural, functional, among others. There are also libraries with functional features such as itertools or 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

Walk

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 like a 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 map, a 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 filter, which 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 itertools, a module designed to make efficient loops in iterable objects, based on languages such as Haskell and SML. In fact, you already know some functions of this module like map and filter, but now they come with the whole family and on steroids.

Get started with Fluid Attacks' Secure Code Review solution right now

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 functools, a 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'

You can even find fantastic external libraries that will help you to raise your code to a higher functional level. Some of them are PyMonad and Pydash.

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.

"Meme about functional Python"

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).

Conclusions

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.

What about the security of your code? Have you read our post on secure code review?

Subscribe to our blog

Sign up for Fluid Attacks' weekly newsletter.

Recommended blog posts

You might be interested in the following related posts.

Photo by James Lee on Unsplash

A lesson of this global IT crash is to shift left

Photo by CardMapr on Unsplash

Users put their trust in you; they must be protected

Photo by Towfiqu barbhuiya on Unsplash

Ensuring compliance and security in the banking sector

Photo by Andre Taissin on Unsplash

With great convenience comes increased risk

Photo by FlyD on Unsplash

Software supply chain management in financial services

Photo by Robs on Unsplash

Consequential data breaches in the financial sector

Photo by Towfiqu barbhuiya on Unsplash

Data protection in the financial sector, tips and more

Start your 21-day free trial

Discover the benefits of our Continuous Hacking solution, which hundreds of organizations are already enjoying.

Start your 21-day free trial
Fluid Logo Footer

Hacking software for over 20 years

Fluid Attacks tests applications and other systems, covering all software development stages. Our team assists clients in quickly identifying and managing vulnerabilities to reduce the risk of incidents and deploy secure technology.

Copyright © 0 Fluid Attacks. We hack your software. All rights reserved.