A function is a block of organized, reusable code that is used to perform a single, related action. Functions provide better modularity for your application and a high degree of code reuse. In Python, a function is defined using the “def” keyword, followed by the function name and a set of parentheses that may include parameters. The code within the function is indented and runs when the function is called. Functions can return values, or they can simply perform an action without returning anything.
With functional programming comes the issue of Pure and Impure functions. A pure function is a function that has no side effects and a function that returns something based on its argument value. Such as –
def pure_function(a,b): c = (2 * a) + (2 * b) return c res = pure_function(5,10) print(res)
In the above program, pure_function takes two arguments and returns a value by making some calculations on them. From start to finish this function does not depend on any external value or is associated with changing any external value. It can be called a pure function.
an impure function is a function that not only takes inputs and returns an output but also modifies some external state. An impure function may have side effects, which are actions that occur beyond the function’s output. These side effects can include changing the state of global variables, reading input from a user or file, or writing output to a file or a network.
Impure functions can be difficult to reason about because their output depends not only on their inputs but also on the current state of the program. This makes it challenging to predict the behavior of the program and can lead to bugs and unexpected results.
However, impure functions can also be useful in certain situations. For example, if we need to perform an action that changes the state of a program, like writing to a file, we need to use an impure function. In these cases, it is important to ensure that the function is used appropriately and that its side effects are properly managed.
my_list =  def impure_function(arg): my_list.append(arg) impure_function(38) print(my_list)
When a value goes to impure_function at the top, It is inserting that value into a list whose name is on the outside, my_list. The functional boundaries of this function are a little extra. This is called the impure_function.
Simply say, it is a programming style that relies exclusively on functions. The higher-order functions are the main thing in this genre. A function that can take another function as an argument and return a function as a return element is called a higher-order function. Such as –
def first_func(func, arg): return func(func(arg)) def add(x): return x + 5 print(first_func(add, 10))
In the example above, we first call the first_func function and send it a function and a value according to its definition. The function I sent is the add function and value 10. On the other hand, I am taking that add function as a func argument in the first_func function and calling it more than once. Again, func or add function takes an argument. So, for the first time, I am sending 10 of them during the execution and the return is 15 and for the second time, I am getting that 15 and getting the final 20 as the result.
Normally, a function is created using the def keyword. It is automatically assigned to a variable that can be used to call it next. On the other hand, string or integer-type values can be easily created without assigning them to any variables. This feature can also be used for functions (without assigning variables) and via lambda. Functions created in this way are called anonymous functions.
The use of Lambda is very effective when it is very simple to send a function of one line as an argument to another function later. That is when it seems pointless to define/create a function that works in one line with a different def.
lambda x, ya: x + ya First, the lambda keyword is written and its arguments are written and after giving a colon this lambda or function of the function is written. For example, this lambda takes two arguments and adds them to work –
def my_function(func, arg): return func(arg) print(my_function(lambda x: 2 * x, 5))
In the example above, my_function takes a function and a value as arguments. Next, when we call my_function and feel the need to send a function and a value in it, we send a lambda. As lambda x: 2 * x and 5 without sending the function. Meanwhile, my_function is executing that lambda as a function and since that lambda function again has an argument x, it is forwarding its received argument to 5.
Map and filter
Maps and filters are useful for various operations on lists and similar objects called iterable in Python. These are built-in functions.
The map function takes a function and an iterable as its argument. The sent function is applied to virtually every element of that iterable. Returns the modified iterable survival at the end. Such as –
def make_double(x): return x * 2 marks = [101, 121, 201, 301] result = map(make_double, marks) print(list(result))
[202, 242, 402, 602]
In the example above, we first defined a simple function whose function is to return any number that comes close to it by doubling. Then we defined another list that has some numbers in it. Then we call the map function and send the make_double function as its first argument and the my_marks list (iterable) as the second argument. The map function returns another iterable in the result variable which is actually twice the value of the previous list. Finally, before printing, I converted that iterable into a list and printed it.
The name of the filter function makes it clear that it filters something. This function removes some elements from an iterable given to it based on a prediction (predict is a function that returns a boolean value). Like maps, filters also take two arguments – a function and an iterable (list).
The filter removes all the elements for which the return or prediction of the function sent to it is false. The following example will make it clear –
def is_odd(x): return x % 2 != 0 marks = [101, 202, 301, 404, 501, 601] result = filter(is_odd, marks) print(list(result))
[101, 301, 501, 601]
The is_odd function returns True if the value attached to it is True and False returns otherwise. And we sent this function as the first argument of the filter. On the other hand, I sent marks as iterable. Now the filter function applies that function to every element in our list and when its return is False it removes the element and returns a new object at the end.
Recursion is a very important issue in functional programming. Simply say, recursion is a condition where a function calls itself.
A problem that can be broken down into smaller parts to solve, and the work of each part will be the same again, in which case recursive function i.e. recursion is very useful.
As many know about the factorial, the factorial of a number means the overall product of each of the consecutive numbers starting from that number.
That is, the factorial of 5 = 5x4x3x2x1 = 120
It can also be thought of as,
Factorial of 5
= 5x (factorial of 4)
= 5x4x (factorial of 3)
= 5x4x3 (factorial of 2) = 5x4x3x2 (factorial of 1)
That means doing the same thing every time but for different numbers. And this function only works if there is only one. So what can be done? To call the same function over and over again means to call oneself to a certain time of unity.
def factorial(x): if x == 1: return 1 else: return x * factorial(x-1) print(factorial(5))