Lazy evaluation in Python

Lazy evaluation is a code optimization strategy in which repetitive evaluations are omitted by evaluating expressions only when they are required. This strategy can be helpful when we need to compute a time-consuming expression needed only a few times. It’s counter part is strict evaluation, which involves immediate evaluation of Pythonic expressions. Although being lazy is considered bad in the real world but in programming it can actually be fruitful and sometimes even more efficient by saving precious resources. We have been using lazy evaluation functions for the longest time without being aware of it. In this Answer, we’ll go through some of these functions and dive deep into the benefits and limitations of lazy evaluation.

Lazy evaluation functions

Let’s review some of the functions commonly used to implement lazy evaluation in Python.

1. range()

The range() method is a more efficient way of traversing Python lists, saving both memory and time. In the code given below, we create two ranges. The first my_range_1 returns a list of six elements, while the second returns 666 items. However, despite the great difference between the number of list items returned, the size of the range object returned is the same for both ranges. This is because range() does not immediately create a list of items in memory. Instead, it only stores the starting, step, and stopping values in memory while each item in the range is computed when required.

import sys
my_range_1 = range(6)
my_range_2 = range(666)
print(sys.getsizeof(my_range_1))
print(sys.getsizeof(my_range_2))

2. zip()

The zip() function returns a tuple created by merging two iterables. This method is an example of a generatorA function that creates iterators. that creates sequences on demand in a more time and memory-efficient manner.

my_list_1 = [1, 2, 3, 4]
my_list_2 = ['a', 'b', 'c', 'd']
zipped = zip(my_list_1, my_list_2) # Use zip() to merge the two lists into tuples
zipped_list = list(zipped) # Convert the zipped object to a list of tuples
print(zipped_list)

3. open()

The open() method is another generator method that returns an iterable file object. Instead of reading the entire file at once, it only reads the file parts that are requested while iterating via the generator.

main.py
my_file.txt
with open("my_file.txt", "r") as file_reader:
for one_line in file_reader:
print(one_line)

4. lambda and map functions

A lambda function is another way to implement lazy evaluation in Python. This anonymous function does not take up space in memory. Moreover, we further optimize our code by using the map function. It will call the lambda function for all items in an iterable like a list.

my_map_object = map(lambda x : x*x + 2, [1,10,5])
print(my_map_object)

Benefits and limitations of lazy evaluation

The following section shows the ups and downs of using lazy evaluation in our Python code.

Benefits

Limitations

Increased code performance

Debugging errors may become difficult

Time and memory optimization

Memory leaks

Flexibility in evaluating large-scale processing tasks

In non-functional languages, implementing lazy evaluation may be complex

Conclusion

To wrap things up, sometimes being lazy might be the quickest and most efficient way to get something done. This is true for both real life and for the Python programming paradigm. With lazy evaluation functions like range(), map() and zip() etc., we can efficiently manage both memory allocation and execution time.

Free Resources

Copyright ©2024 Educative, Inc. All rights reserved