Topics: Coronavirus | AI | Data Science | Deep Learning | Machine Learning | Python | R | Statistics

KDnuggets Home » News » 2018 » Feb » Tutorials, Overviews » Introduction to Functional Programming in Python ( 18:n10 )

# 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. comments

### The Map Function

While the ability to pass in functions as arguments is not unique to Python, it is a recent development in programming languages. Functions that allow for this type of behavior are called first-class functions. Any language that contains first-class functions can be written in a functional style.

There are a set of important first-class functions that are commonly used within the functional paradigm. These functions take in a Python iterable, and, like `sorted()`, apply a function for each element in the list. Over the next few sections, we will examine each of these functions, but they all follow the general form of `function_name(function_to_apply, iterable_of_elements)`.

The first function we'll work with is the `map()` function. The `map()` function takes in an iterable (ie. `list`), and creates a new iterable object, a special `map` object. The new object has the first-class function applied to every element.

```# Pseudocode for map.
def map(func, seq):
# Return `Map` object with
# the function applied to every
# element.
return Map(
func(x)
for x in seq
)
```

Here's how we could use map to add `10` or `20` to every element in a list:

```values = [1, 2, 3, 4, 5]

# Note: We convert the returned map object to
# a list data structure.
add_10 = list(map(lambda x: x + 10, values))
add_20 = list(map(lambda x: x + 20, values))

>> [11, 12, 13, 14, 15]

>> [21, 22, 23, 24, 25]
```

Note that it's important to cast the return value from `map()` as a `list` object. Using the returned `map` object is difficult to work with if you're expecting it to function like a `list`. First, printing it does not show each of its items, and secondly, you can only iterate over it once.

### The Filter Function

The second function we'll work with is the `filter()` function. The `filter()` function takes in an iterable, creates a new iterable object (again, a special `map` object), and a first-class function that must return a `bool` value. The new `map` object is a filtered iterable of all elements that returned `True`.

```# Pseudocode for filter.
def filter(evaluate, seq):
# Return `Map` object with
# the evaluate function applied to every
# element.
return Map(
x for x in seq
if evaluate(x) is True
)
```

Here's how we could filter odd or even values from a list:

```values = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

# Note: We convert the returned filter object to
# a list data structure.
even = list(filter(lambda x: x % 2 == 0, values))
odd = list(filter(lambda x: x % 2 == 1, values))

print(even)
>> [2, 4, 6, 8, 10]

print(odd)
>> [1, 3, 5, 7, 9]
```

### The Reduce Function

The last function we'll look at is the `reduce()` function from the `functools` package. The `reduce()` function takes in an iterable, and then reduces the iterable to a single value. Reduce is different from `filter()` and `map()`, because `reduce()` takes in a function that has two input values.

Here's an example of how we can use `reduce()` to sum all elements in a list.

```from functools import reduce

values = [1, 2, 3, 4]

summed = reduce(lambda a, b: a + b, values)
print(summed)
>> 10
``` An interesting note to make is that you do not have to operate on the second value in the `lambda` expression. For example, you can write a function that always returns the first value of an iterable:

```from functools import reduce

values = [1, 2, 3, 4, 5]

# By convention, we add `_` as a placeholder for an input
# we do not use.
first_value = reduce(lambda a, _: a, values)
print(first_value)
>> 1
```

### Rewriting with list comprehensions

Because we eventually convert to lists, we should rewrite the `map()` and `filter()` functions using list comprehension instead. This is the more pythonic way of writing them, as we are taking advantage of the Python syntax for making lists. Here's how you could translate the previous examples of `map()` and `filter()` to list comprehensions:

```values = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

# Map.
add_10 = [x + 10 for x in values]
>> [11, 12, 13, 14, 15, 16, 17, 18, 19, 20]

# Filter.
even = [x for x in values if x % 2 == 0]
print(even)
>> [2, 4, 6, 8, 10]
```

From the examples, you can see that we don't need to add the lambda expressions. If you are looking to add `map()`, or `filter()` functions to your own code, this is usually the recommended way. However, in the next section, we'll provide a case to still use the `map()`and `filter()` functions.

### Writing Function Partials

Sometimes we want to use the behavior of a function, but decrease the number of arguments it takes. The purpose is to "save" one of the inputs, and create a new function that defaults the behavior using the saved input. Suppose we wanted to write a function that would always add 2 to any number:

```def add_two(b):
return 2 + b

>> 6
```

The `add_two` function is similar to the general function, \$f(a,b) = a + b\$, only it defaults one of the arguments (\$a = 2\$). In Python, we can use the `partial` module from the `functools`package to set these argument defaults. The `partial` module takes in a function, and "freezes" any number of args (or kwargs), starting from the first argument, then returns a new function with the default inputs.

```from functools import partial

return a + b

>> 6

>> 14
```

Partials can take in any function, including ones from the standard library.

```# A partial that grabs IP addresses using
# the `map` function from the standard library.
extract_ips = partial(
map,
lambda x: x.split(' ')
)
```

### Next steps

In this post, we introduced the paradigm of functional programming. We learned about the lambda expression in Python, important functional functions, and the concept of partials. Overall, we showed that Python provides a programmer with the tools to easily switch between functional programming and object-oriented programming.

If you've enjoyed functional programming, our newest course: Building a Data Pipeline uses functional programming concepts to build a data pipeline. In this course, you'll find more advanced Python concepts, examples of good API design, and a final project that uses your own data pipeline built from scratch!

Bio: Spiro Sideris is a Data Engineer content author at Dataquest.io. A software engineer with a knack for economics and a love for mathematics.

Original. Reposted with permission.

Related: Get KDnuggets, a leading newsletter on AI, Data Science, and Machine Learning