Functional Programming in Python

Functional Programming in Python

What is Functional Programming?

Paradigm can be termed as a method to solve some problem or do some task.

Functional programming is a programming paradigm that focuses on functions and avoids shared state, mutating state, and side effects. This paradigm uses the approach of “what to solve” instead of “how to solve”. It involves many techniques and concepts. In this article, we will focus on three aspects of functional programming, which are:

  • Nested Functions
  • Lambda Functions
  • Higher-order Functions

Higher-order Functions

A function that accepts other functions in its parameters is known as a higher-order function. Higher-order functions are often used to process the elements in a list. Before seeing an example of using a higher-order function to process a list, first consider the program in sample 1 that doesn't use a higher-order function, but instead uses a for loop to convert a list of temperatures from Fahrenheit to Celsius.

# Sample 1

def main():
    fahr_temps = [72, 65, 71, 75, 82, 87, 68]

    # Print the Fahrenheit temperatures.
    print(f"Fahrenheit: {fahr_temps}")

    # Convert each Fahrenheit temperature to Celsius and store
    # the Celsius temperatures in a list named cels_temps.
    cels_temps = []
    for fahr in fahr_temps:
        cels = cels_from_fahr(fahr)
        cels_temps.append(cels)

    # Print the Celsius temperatures.
    print(f"Celsius: {cels_temps}")


def cels_from_fahr(fahr):
    """Convert a Fahrenheit temperature to
    Celsius and return the Celsius temperature.
    """
    cels = (fahr - 32) * 5 / 9
    return round(cels, 1)


# Call main to start this program.
if __name__ == "__main__":
    main()
 >  python sample_1.py 
 Fahrenheit: [72, 65, 71, 75, 82, 87, 68] 
 Celsius: [22.2, 18.3, 21.7, 23.9, 27.8, 30.6, 20.0]

In this example, we used a for loop in iterating through the fahr_temps list, then we converted each fahr temp in the list to a cels temp. Finally, we appended the converted temp to a new list named cels_temp. Writing a for loop like this is the traditional/procedural way to process all the elements in a list, and doesn't use higher-order functions.

Python includes a built-in higher-order function named map that will process all the elements in a list and return a new list that contains the results. The map function accepts a function and a list as arguments and contains a loop inside it, so that when a programmer calls the map function, he doesn't need to write a loop. The map function is a higher-order function because it accepts a function as an argument. Consider the program in sample 2 that produces the same results as sample 1.

# Sample 2

def main():
    fahr_temps = [72, 65, 71, 75, 82, 87, 68]

    # Print the Fahrenheit temperatures.
    print(f"Fahrenheit: {fahr_temps}")

    # Convert each Fahrenheit temperature to Celsius and store
    # the Celsius temperatures in a list named cels_temps.
    cels_temps = list(map(cels_from_fahr, fahr_temps))

    # Print the Celsius temperatures.
    print(f"Celsius: {cels_temps}")


def cels_from_fahr(fahr):
    """Convert a Fahrenheit temperature to
    Celsius and return the Celsius temperature.
    """
    cels = (fahr - 32) * 5 / 9
    return round(cels, 1)


# Call main to start this program.
if __name__ == "__main__":
    main()
 >  python sample_2.py 
 Fahrenheit: [72, 65, 71, 75, 82, 87, 68] 
 Celsius: [22.2, 18.3, 21.7, 23.9, 27.8, 30.6, 20.0]

Notice that sample 2, doesn't contain a for loop. Instead, it contains a call to the map function. Remember that the map function has a loop inside it, so that the programmer who calls map, doesn't have to write the loop. Notice also that the first argument to the map function is the name of the cels_from_fahr function. In other words, we are passing the cels_from_fahr function into the map function, so that map will call cels_from_fahr for each element in the fahr_temps list.

The map function is just one example of a higher-order function. Python also includes the built-in higher-order sorted and filter functions and several higher-order functions in the functools module.

Lambda Functions

Lambda Function, also referred to as ‘Anonymous function’ is same as a regular python function but can be defined without a name. While normal functions are defined using the def keyword, anonymous functions are defined using the lambda keyword. However,they are restricted to single line of expression. They can take in mutliple parameters as in regular functions.

The syntax for lambda function is given by : lambda param1, param2, … paramN: expression As shown in the template, type the keyword lambda, then parameters separated by commas, then a colon (:), and finally a single expression that performs arithmetic, modifies a string, or computes something else. There is no return statement which is usually present in the def function syntax. The function will simply return the expression value even when there is no return statement.

Consider the program in sample 3 which is yet another example program that converts Fahrenheit temperatures to Celsius.

# Sample 3

def main():
    fahr_temps = [72, 65, 71, 75, 82, 87, 68]

    # Print the Fahrenheit temperatures.
    print(f"Fahrenheit: {fahr_temps}")

    # Define a lambda function that converts
    # a Fahrenheit temperature to Celsius and
    # returns the Celsius temperature.
    cels_from_fahr = lambda fahr: round((fahr - 32) * 5 / 9, 1)

    # Convert each Fahrenheit temperature to Celsius and store
    # the Celsius temperatures in a list named cels_temps.
    cels_temps = list(map(cels_from_fahr, fahr_temps))

    # Print the Celsius temperatures.
    print(f"Celsius: {cels_temps}")


# Call main to start this program.
if __name__ == "__main__":
    main()
 >  python sample_3.py 
 Fahrenheit: [72, 65, 71, 75, 82, 87, 68] 
 Celsius: [22.2, 18.3, 21.7, 23.9, 27.8, 30.6, 20.0]

Notice the lambda function in this sample takes one parameter named fahr and computes and returns the corresponding Celsius temperature. The lambda function is passed into the map function.

Looking at the lambda function we just wrote, it appears that the lambda function is named cels_from_fahr. However, cels_from_fahr is the name of a variable, not the name of the lambda function. The lambda function has no name. This distinction may seem trivial until we see an example of an inline lambda function. Notice in the next example that the lambda function is defined inside the parentheses for the call to the map function.

    # Convert each Fahrenheit temperature to Celsius and store
    # the Celsius temperatures in a list named cels_temps.
    cels_temps = list(map(
            lambda fahr: round((fahr - 32) * 5 / 9, 1),
            fahr_temps))

Nested Functions

A nested function, also referred to as an inner function is a function that is defined inside another function and is useful when we wish to split a large function into smaller functions . To define a nested function, just initialize another function within a function by using the def keyword.

There are times when you want to prevent a function or the data it has access to, from being accessed from other parts of your code, so you can encapsulate it within another function. When you nest a function like this, it's hidden from the global scope.

The program in sample 4 produces the same results as samples 1, 2 and 3, but it uses a nested function.

# Sample 4

def main():

    def cels_from_fahr(fahr):
        """Convert a Fahrenheit temperature to
        Celsius and return the Celsius temperature.
        """
        cels = (fahr - 32) * 5 / 9
        return round(cels, 1)

    fahr_temps = [72, 65, 71, 75, 82, 87, 68]

    # Print the Fahrenheit temperatures.
    print(f"Fahrenheit: {fahr_temps}")

    # Convert each Fahrenheit temperature to Celsius and store
    # the Celsius temperatures in a list named cels_temps.
    cels_temps = list(map(cels_from_fahr, fahr_temps))

    # Print the Celsius temperatures.
    print(f"Celsius: {cels_temps}")


# Call main to start this program.
if __name__ == "__main__":
    main()
 >  python sample_4.py 
 Fahrenheit: [72, 65, 71, 75, 82, 87, 68] 
 Celsius: [22.2, 18.3, 21.7, 23.9, 27.8, 30.6, 20.0]

In the code above, the inner function is only available from within the function outer. If you try to call inner from outside the function, you'll get a NameError. Instead, you must call the smaller function (cels_from_fahr(fahr)) from the containing function (main()) only.

Conclusion

Finally! We are at the end of this lesson 😁.

I know, it is a lot to take in at a time. But, you don't need to remember everything that I have mentioned here at this point. There are some other methods as well that I have not mentioned here

If you want to know more about the concepts we covered here, kindly check out the resources below:


That was it. Thank you for reading.

Let me know if you need any help or want to discuss something. Reach out to me on Instagram. Make sure to share any thoughts, questions, or concerns. I would love to see them.

Kindly like, follow, or 👇

buy me a coffee