Introduction to Functional Programming in Python
Python facilitates different approaches to writing code, and while an object-oriented approach is common, an alternative and useful style of writing code is functional programming.
By Spiro Sideris, Dataquest.io
Most of us have been introduced to Python as an object-oriented language; a language exclusively using classes to build our programs. While classes, and objects, are easy to start working with, there are other ways to write your Python code. Languages like Java can make it hard to move away from object-oriented thinking, but Python makes it easy.
Given that Python facilitates different approaches to writing code, a logical follow-up question is: what is a different way to write code? While there are several answers to this question, the most common alternative style of writing code is called functional programming. Functional programming gets its name from writing functions which provides the main source of logic in a program.
In this post, we will:
- Explain the basics of functional programming by comparing it to object-oriented programming.
- Cover why you might want to incorporate functional programming in your own code.
- Show you how Python allows you to switch between the two.
Comparing object-oriented to functional
The easiest way to introduce functional programming is to compare it to something we're already aware of: object-oriented programming. Suppose we wanted to create a line counter class that takes in a file, reads each line, then counts the total amount of lines in the file. Using a class, it could look something like the following:
While not the best implementation, it does provide an insight into object-oriented design. Within the class, there are the familiar concepts of methods and properties. The properties set and retrieve the state of the object, and the methods manipulate that state.
For both these concepts to work, the object's state must change over time. This change of state is evident in the
lines property after calling the
read() method. As an example, here's how we would use this class:
The ever-changing state of an object is both its blessing and curse. To understand why a changing state can be seen as a negative, we have to introduce an alternative. The alternative is to build the line counter as a series of independent functions.
Working with pure functions
In the previous example, we were able to count the lines only with the use of functions. When we only use functions, we are applying a functional approach to programming which is, non-excitingly, called functional programming. The concepts behind functional programming requires functions to be stateless, and rely only on their given inputs to produce an output.
The functions that meet the above criteria are called pure functions. Here's an example to highlight the difference between pure functions, and non-pure:
The benefit of using pure functions over impure (non-pure) functions is the reduction of side effects. Side effects occur when there are changes performed within a function's operation that are outside its scope. For example, they occur when we change the state of an object, perform any I/O operation, or even call
Programmers reduce side effects in their code to make it easier to follow, test, and debug. The more side effects a codebase has, the harder it is to step through a program and understand its sequence of execution.
While it's convienent to try and eliminate all side effects, they're often used to make programming easier. If we were to ban all side effects, then you wouldn't be able to read in a file, call print, or even assign a variable within a function. Advocates for functional programming understand this tradeoff, and try to eliminate side effects where possible without sacrificing development implementation time.
The Lambda Expression
Instead of the
def syntax for function declaration, we can use a
lambda expression to write Python functions. The lambda syntax closely follows the
def syntax, but it's not a 1-to-1 mapping. Here's an example of building a function that adds two integers:
lambda expression takes in a comma seperated sequences of inputs (like
def). Then, immediately following the colon, it returns the expression without using an explicit return statement. Finally, when assigning the
lambda expression to a variable, it acts exactly like a Python function, and can be called using the the function call syntax:
If we didn't assign
lambda to a variable name, it would be called an anonymous function. These anonymous functions are extremely helpful, especially when using them as an input for another function. For example, the
sorted() function takes in an optional
key argument (a function) that describes how the items in a list should be sorted.