Python- First Class Functions

Conceptually, “first class functions” is a feature of a programming language. Several programming language like Lisp, Haskell, Scala, Julia, Python, JavaScript, Ruby, Perl, Go etc. supports the “First Class Function”. In a nutshell, all functions in Python are first class functions. When we say first class function in any programming language, the language treats the function as any other variable, it can be passed and manipulated similarly how we treat other kind of objects (In Python all are treated as objects) like integer, string.

Properties First Class Functions

  • Allows to store the function in a variable.
  • Allows to pass the function as a parameter to another function.
  • Allows to return the function from a function.
  • Allows to store then in data structures such as list, dictionaries and tuple.
Stores the function as variable:

This feature can be illustrated with the below snippet of code.

# File name :
# Function Definition
def wish_the_world(message):
    return "Hello, there, {0}".format(message)

# Call the function with a message
print(wish_the_world("Good Morning!"))

# Store function as variable
wish_good_afternoon = wish_the_world

# printing, will print the memory location of function. 

# Calling the function which is stored as variable
print(wish_good_afternoon("Good Afternoon!"))

Here is the result of the above python code.

Hello, there, Good Morning!
<function wish_the_world at 0x7f698c6536e0>
Hello, there, Good Afternoon!

Let me explain the above code. We have started with the defining a function called ‘wish_the_world’ which takes an argument called the ‘message’. The function returns the message ‘Hello, there’ with the given argument. In the next line, we call the function with message ‘_Good Morning!_’, this displays the message in the output as ‘Hello, there, Good Morning!

Following line, we assign the function ‘wish_the_world’ to a variable. Here we are able to store the function as variable. Now, when we try to print the variable, the interpreter will displays ‘<function wish_the_world at 0x7f698c6536e0>’ which says the variable ‘wish_good_afternoon’ is pointing to the function ‘wish_the_world’. There is also a small information about the memory location where the function is currently residing at machine memory.

If you want to call the function which is stored as variable, you have to call with with ‘()’. In the next line we have called the function ‘wish_good_afternoon(“Good Afternoon!”)’ with a message.

Pass the function as argument to another function:

Below is small code snippet which shows the function passed as argument to another function.

# File Name :
# Multiply by 2
def multiply_by_2(x):
    return 2*x
# Function which takes first argument as function.

def multiplication_table(fun, multiple, arg_list):
    for item in arg_list:
        print("{0} x {1} = {2}".format(multiple, item, fun(item)))

# Calling the function to display the multiplication table
multiplication_table(multiply_by_2, 2, range(1,6))

When we run the above code, here is the result.

MyShell-$ python
2 x 1 = 2
2 x 2 = 4
2 x 3 = 6
2 x 4 = 8
2 x 5 = 10

Here, we have a function ‘multiply_by_2’. The functionality of this function is to multiply the given numbers by 2 and returns the results. We have another function to display the multiplication table, which takes 3 arguments. The first argument is a function, the second one is multiple and the last is the list of numbers. When we call the function ‘multiplication_table’ with arguments ‘multiplication_table(multiply_by_2, 2, range(1,6))‘, for each number in numbers list, the function ‘multiply_by_2’ is called and it will display the multiplication table for 2.
One can see that the function ‘multiply_by_2’ is passed to the function ‘multiplication_table’

Return the function from function:

Here is the illustration of the return the function from a function.

# File Name:
# Log Levels
log_levels = {1:"DEBUG", 2:"INFO", 3:"WARNING", 4:"CRITICAL", 5:"ERROR"}

def logger(log_level):
    def wrap_log(message):
        print("{0}::{1}".format(log_level, message))
    return wrap_log

# defining individaul log functions.
log_debug = logger(log_levels[1])
log_info = logger(log_levels[2])
log_warning = logger(log_levels[3])
log_critical = logger(log_levels[4])
log_error = logger(log_levels[5])

# Based on log levels, functions can be called by  passing the releant message.
log_debug("This is debug log.")
log_info("This is information log.")
log_warning("This is warning log.")
log_critical("This is critical log.")
log_error("This is error log")

When we run the above snippet, this is the result

DEBUG::This is debug log.
INFO::This is information log.
WARNING::This is warning log.
CRITICAL::This is critical log.
ERROR::This is error log

In the above code, we have defined a dictionary ‘log_levels’ which contain the log levels such as

We have defined a function called ‘logger’, which takes an argument log level. Inside the function ‘logger’, we another inner function ‘wrap_log’, which takes message as argument and prints the both log level as well as the message. In the main function ‘logger’, we are returning the ‘wrap_log’ function without calling it. (Note that we have not used ‘()’ while returning the function)

Next, we have defined the different log functions based on the log levels, by passing log_levels to the each function. When we run the ‘log_error = logger(log_levels[5])’, the interpreter calls the outer function (‘logger’) with log level ‘ERROR’. Inside the function ‘logger’, we are defining a wrapper function ‘wrap_log’, which takes an argument ‘message’. The print in the wrapper function prints the log level and the message to the console. Please note the return statement in the function logger, we are just returning the function as variable reference not calling the function.

Based on the logging levels, the particular log function can be called. As an example, in case of any error, we can call the function ‘log_error(“This is error log”)’ by passing the error message to the function. This will calls the wrapper function ‘wrap_logger’ with the error message and prints the ‘ERROR::This is error log’ in the terminal.

Functions stored in the data structures:

This code snippet illustrates, function stores in data structures with following code implementation.

# File Name:
# General function to store in 
def function_in_ds(ds,message):
    print("Data Structure is '{0}'. Message:{1}".format(ds, message))

# Storing the 'function_ib_ds' in data structures
my_list = [function_in_ds]
my_tuple = [function_in_ds]
my_dict = {1:function_in_ds}

# Calling the functions
my_list[0]("List","Good Morning!")
my_tuple[0]("Tuple","Good Afternoon!")
my_dict[1]("Dictionary", "Good Evening!")

When we run the above code, it will print the below results.

Data Structure is 'List'. Message:Good Morning!
Data Structure is 'Tuple'. Message:Good Afternoon!
Data Structure is 'Dictionary'. Message:Good Evening!

The above illustration is simple. We have function ‘function_in_ds’, which takes two arguments (data structure name and message). and prints them to the console. As mentioned in the code, we are assigning the function to the list, tuple, dictionary as the function reference. While calling, we can call the reference of list tuple and dictionary with the respective arguments.

Thin line between “First Class Functions” and “Higher Order Functions”

While going through the references from the web for deeper understanding on these topics, you may come across the term ‘Higher order Functions’. There is thin difference between “First Class Functions” and “Higher Order Functions.”

First Class Functions Higher Order Functions
Concept only limited with functions in programming language. More in general sense, like it can be applied in mathematics.
ITreated as variable, can be assigned to variable or passed as argument. It receives another function as an argument or returns First-order a new function or both.
First class function has capabilities of Higher Order Function. Higher Order Function does not have the capabilities of First Class Function.