Function Programming Python Lambda, Python Iterators, Python Generators, Python List Comprehensions
Table of Contents
Functional Programming
Python supports a form of programming called Functional Programming (FP) that involves programming with functions where functions can be passed, stored, and returned. FP decomposes a problem into a set of functions. The gist of FP is that every function is understood solely in terms of its inputs and its outputs.
Amazon Purchase Links:
*Please Note: These are affiliate links. I may make a commission if you buy the components through these links. I would appreciate your support in this way!
Python Lambda
Small anonymous method can be created with the lambda keyword. Lambda functions are created without using def keyword and without a function name. They are syntactically restricted to a single expression. Semantically, they are just syntactic sugar for a normal method definition. The syntax for lambda function is,
lambda argument_list: expression Keyword
Here, lambda is a keyword, argument_list is a comma separated list of arguments, and expression is an arithmetic expression using these arguments lists. A colon separates both argument_list and expression. No need to enclose argument_list within brackets. For example,
1 2 3 4 5 |
>>> addition_operation = lambda a, b: a + b >>> addition_operation(100, 8) 108 |
In the above code, the lambda function takes two arguments a and b and performs an addition operation using these arguments. You can assign a lambda function to a variable and use this variable as a function name to pass arguments. Note, you are not assigning the value of lambda function to the variable; instead you are giving a function name to a lambda expression. A lambda function returns the result of the expression implicitly, and there is no need to specify a return keyword.
Python Iterators
A Python language feature, iterators, is an important foundation for writing functionalstyle programs. Iteration is a routine term for taking each item of something, one after another. Any time you use a loop to go over a group of items, that is an iteration. In Python, iterable and iterator have specific meanings.
An iterable is an object that has an iter() method that returns an iterator. So, an iterable is an item that you can get an iterator from. Lists, dictionaries, tuples, and strings are iterable in Python.
An iterator is an object with a next() method. Whenever you use a for loop in Python, the next() method is called automatically to get each item from the iterator, thus going through the process of iteration. Iterators are stateful, meaning once you have consumed an item from them, it’s gone. You can call the next() method using the next() and iter() method using iter() built-in functions. For example,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
>>> phone = "jio" >>> it_object = iter(phone) >>> type(it_object) <class 'str_iterator'> >>> next(it_object) 'j' >>> next(it_object) 'i' >>> next(it_object) 'o' 343 Introduction to Data Science >>> next(it_object) Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration |
An iterator is an item representing a stream of data; this item returns the data one element at a time. A Python iterator must support a function called next() that takes no arguments and always returns the next element of the stream. If there are no more elements in the stream, next() must boost the StopIteration exception. The built-in iter() function takes an arbitrary object and tries to return an iterator that will return the object’s contents or elements, else raises TypeError exception if the object does not support iteration.
Python Generators
Generators are a special class of methods that simplify the task of writing iterators. Regular method compute a value and return it, but generators return an iterator that returns a stream of values. When you call a function, its local variables have their own scope. After the return statement is executed in a function, the local variables are destroyed and the value is returned to the caller. Later, a call to the same function creates a fresh set of local variables that have their own scope. However, what if the local variables were not thrown away on exiting a function? What if you could later resume the function from where it left off? This is what generators provide; they can be thought of as resumable functions. A generator function does not include a return statement. Here’s the simplest example of a generator function,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
>>> def generate_ints(N): >>> for i in range(N): >>>yield i >>> gen = generate_ints(3) >>> gen <generator object generate_ints at 0x00000160E4D26410> >>> next(gen) 0 >>> next(gen) 1 >>> next(gen) 2 >>> next(gen) Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration |
Any method containing a yield keyword is a generator function. When you call a generator function, it does not return a single value. Instead it returns a generator object that supports the iterator next() method. Inside the for loop on executing the yield expression, the generator outputs the value of i, similar to a return statement. The main changes between yield and a return statement is that on reaching a yield the generator’s state of execution is temporarily suspended and local variables are preserved. On the next call to the generator’s next() method, the function will resume execution from where
it left off. In the real world, generator functions are used for calculating large sets of results where you do not know if you are going to need all results.
Python List Comprehensions
List comprehensions provide a concise way to make lists. Common applications of list comprehensions are to create new lists where each element is the result of some operation applied to each member of another sequence or iterable or to create a subsequence of those items that satisfy a certain condition.
list_variable = [variable[expression] for variable in input [predicate]]
A list comprehension consists of brackets containing a variable or First Part) followed by a for clause (Middle Part), then predicate True or False using an if clause. The components expression and predicate are optional. The new list resulting from evaluating the expression in the context of the for and if clauses that follow it will be assigned to the list_variable. The variable represents members of input. The order of execution in a list comprehension is (a) If the if condition is not specified, then Middle Part and First Part gets executed; (b) If the if condition is specified, then the Middle Part, Last Part, and First Part gets executed. For example,
1 2 3 4 5 6 7 8 9 |
>>> shahzada_fawad = [] >>> for number in '1729': >>shahzada_fawad.append(number) >>> shahzada_fawad ['1', '7', '2', '9'] |
In the above code, an empty list shahzada_fawad is created. Then, you loop through each character in the ‘1729’ string using the number iteration variable. Each of those characters is appended into shahzada_fawad list. Finally, print the list. For the above code, you can have more readable and concise code through list comprehensions.
1 2 3 4 5 |
>>> shahzada_fawad = [number for number in '1729'] >>> shahzada_fawad ['1', '7', '2', '9'] |
Simple for loops can be written as comprehensions offering cleaner and more readable syntax. Comprehensions can be thought of as a compact form of a for loop. In the list comprehension, the variable number indicates the item that will be inserted into the list shahzada_fawad at each step of the for loop. In the for loop, the iterating variable number iterates through each character of the string ‘1729’. The resulting list is assigned to the shahzada_fawad list variable and displayed.
1 2 3 4 5 |
>>> display_upper_case = [each_char.upper() for each_char in "farrago"] >>> display_upper_case ['F', 'A', 'R', 'R', 'A', 'G', 'O'] |
In the above code, the iterating variable each_char iterates through each character of the string “farrago.” While iterating through each character using an each_char iterating variable, each of those characters is converted to upper case using the upper() method and inserted into the display_upper_case list. Print the items of the display_upper_case list.
1 2 3 4 5 |
>>> squares = [x**2 for x in range(1, 10)] >>> squares [1, 4, 9, 16, 25, 36, 49, 64, 81] |
In the above code, numbers from 1 to 9 are generated using the range() function. The iterating variable x iterates through 1 to 9 and at each iteration, the square of the number is found and assigned to squares list. Print the items of the square list.
1 2 3 4 5 |
>>> even_square = [x**2 for x in range(1, 10) if x %2 == 0] >>> even_square [4, 16, 36, 64] |
In the above code, numbers from 1 to 9 are generated using the range() function. Use a for loop to iterate through each number using the iterating variable x. While iterating through each number, the if condition checks whether the number is even or not using a modulus operator. If the number is even, then that number is squared and inserted into the even_ square list. Print the items of even_square list.
1 2 3 4 5 6 7 8 9 |
>>> words = [each_word for each_word in input().split()] petrichor degust jirble flabbergast foppish >>> words.sort() >>> print(" ".join(words)) degust flabbergast foppish jirble petrichor |
In the above code, the input() function requires the user to enter words as input separated by a space. Use the split() function on these entered words to get a list of string items. Use a for loop to iterate through each of these list items using an each_word iterating variable. Insert each of the string items to words list. Then, sort the words list using the sort() method in ascending order according to their ASCII values. Join the string items in words list using join() method and print it