Functools Module in PythonThe functools module, which is included in Python's standard library, provides essential functionality for working with high-order functions (a function that returns a function or takes another function as an argument ). You can reuse or enhance the utility of your functions or callable objects without having to rewrite them using these capabilities. This simplifies the process of building reusable and maintainable code. The functools module has 11 functions in the current stable release, Python 3.8 series, although some of these may not be accessible or work differently in prior or later editions. They are as follows:
Reduce():We'll start with a classic. A function and an iterable are passed to the reduce(function, sequence) function. It applies the supplied function to all members of the iterable in a cumulative manner from left to right before returning a single value. Simply said, it first applies the argument function to the iterable's first two items, and the value returned by this initial call becomes the function's first argument, while the third element of the iterable becomes the second argument. This method is done until the iterable has run out of tables. lru_cache():lru cache() is a decorator that wraps a function in a memoizing callable that saves up to maximize the results of a function call and returns the stored value when the function is called again with the same inputs. When an expensive or I/O bound function is called repeatedly with the same arguments, it can save time. It primarily employs two data structures: a dictionary to map a function's parameters to its output and a linked list to maintain track of the function's call history. LRU Cache stands for Least-Recently-Utilized Cache in full, and it refers to a cache that eliminates the least recently used element when the maximum number of entries is reached. If maxsize is set to None, the LRU feature is disabled, and if typed is True, the LRU feature caches arguments of various data types separately, e.g., f(3) and f(3.0) will be cached separately. In general, the LRU cache should only be used when previously computed values need to be reused. As a result, caching functions that produce different mutable objects on each call isn't a good idea. The positional and keyword inputs to the function must also be hashable, as a dictionary is required to cache the results. partial():Partial functions are derived functions with some input parameters that have already been assigned. If a function takes two parameters, say "a" and "b," a partial function with "a" as a prefilled argument can be built from it, and it can then be called with "b" as the only parameter. The partial() method in Functool is used to construct partial functions/objects, which is an important feature because it allows for:
The partial function also has valuable characteristics that can be used to track partial functions and objects. These are some of them:
partialmethod():The partialmethod() method provides a new partial method descriptor, which is similar to partial but is intended to be used as a method specification rather than a callable method. You can think of it as a method's partial(). singledispatch():Before we get into detail about this function, it's crucial to first review two key concepts: The first is a generic function, which is a function made up of numerous functions that all perform the same task for different types. The dispatch algorithm determines which implementation will be utilized during a call. The second is the Single dispatch, which is a type of generic function dispatch in which the implementation is determined by a single argument's type. With this in mind, the singledispatch decorator in the functool converts a basic function into a generic function whose behavior is determined by the type of its first parameter. It is used for function overloading in plain English. singledispatchmethod():It's a decorator that works in the same way as @singledispatch, but for methods instead of functions. cached_property():The cached property() decorator changes a class method into a property whose value is calculated only once and then cached as a normal attribute throughout the life of the instance, as the name suggests. Except for the caching functionality, it's comparable to @property. It's handy for attributes of instances that are normally functionally permanent but are computationally expensive. total_ordering():Given a class that defines one or more rich comparison ordering methods (equivalent to, =, >, >=, and ==), such as __lt__(), __le__(), __gt__(), __ge__(), or __eq__()). You can define a few comparison methods, and @total ordering will supply the rest based on the definitions you provide. It's critical that the class includes a __eq__() method. If you want to make a class that compares different numbers, for example. All of the rich comparison methods would almost certainly need to be implemented. However, because this is likely to be tiresome and unnecessary, you can just implement the __eq__ and __gt__ methods and rely on @total ordering to fill in the gaps. update_wrapper():It makes a wrapper function's metadata look like the wrapped function. In the case of partial functions, update wrapper(partial, parent) will update the partial function's documentation( doc ) and name( name ) to match the parent function's. wraps():It's just a shortcut for calling update wrapper() on the decorated function. It's the same as calling partial(update wrapper, wrapped=wrapped, assigned=assigned, updated=updated, wrapped=wrapped). cmp_to_key();It converts a key function from an old-style comparison function. Any callable that accepts two parameters, compares them and returns a negative number for less-than, zero for equality, or a positive number for greater-than is referred to as a comparison function. The operator.itemgetter() key function is an example of a callable that accepts one argument and returns another value to be used as the sort key. Tools like sorted(), min(), max(), and itertools.groupby use key functions (). cmp to key() is mostly used as a transition aid for Python 2 scripts with comparison functions. Let us look at the code: Code:Output: Enter your choice according to the below-listed options:: 1. To use the lru_cache() function and compare the time difference between the function with and without the lru_cache(). 2. To use the singledispatch() function and compare the time usage of the functions with and without the singledispatch(). 3. To use the reduce() function understand the various use-cases of the reduce(). 4. To use the partial() function and compare the usage of the functions with and without the partial(). 5. To exit from the code execution. 1 For how many iterations do you want to calculate:: 33 Function with lru_cache took -2.7494192123413086 seconds to calculate Fibonacci for 33 iterations. Function without lru_cache took -1.7327818870544434 seconds to calculate Fibonacci for 33 iterations. To move ahead with code execution enter [y] else [n] y Enter your choice according to the below-listed options:: 1. To use the lru_cache() function and compare the time difference between the function with and without the lru_cache(). 2. To use the singledispatch() function and compare the time usage of the functions with and without the singledispatch(). 3. To use the reduce() function understand the various use-cases of the reduce(). 4. To use the partial() function and compare the usage of the functions with and without the partial(). 5. To exit from the code execution. 2 calling the divide function with the integer parameters( divide_the_numbers(6/4) ), the result is :: 1.5 calling the divide function with the string parameters( divide_the_numbers('12'/'7') ), the result is :: 12/7 To move ahead with code execution enter [y] else [n] y Enter your choice according to the below-listed options:: 1. To use the lru_cache() function and compare the time difference between the function with and without the lru_cache(). 2. To use the singledispatch() function and compare the time usage of the functions with and without the singledispatch(). 3. To use the reduce() function understand the various use-cases of the reduce(). 4. To use the partial() function and compare the usage of the functions with and without the partial(). 5. To exit from the code execution. 3 Enter the length of the list:: 5 100 234 665 230 874 entered list is [100, 234, 665, 230, 874] Using reduce to find the sum of all the elements of the list:: The result of the sum is 2103 Using reduce to find the maximum among all the elements of the list:: Max element is 874 To move ahead with code execution enter [y] else [n] y Enter your choice according to the below-listed options:: 1. To use the lru_cache() function and compare the time difference between the function with and without the lru_cache(). 2. To use the singledispatch() function and compare the time usage of the functions with and without the singledispatch(). 3. To use the reduce() function understand the various use-cases of the reduce(). 4. To use the partial() function and compare the usage of the functions with and without the partial(). 5. To exit from the code execution. 4 Calling the function twice without the use of partial Enter the occupation:: Driver Enter the gadgets used:: Cars Cars are used by the Driver Enter the occupation:: Electrician Enter the gadgets used:: Screwdriver Screwdrivers are used by the Electrician Calling the function twice with the use of partial Enter the occupation:: Teacher Enter the gadgets used:: Books Books are used by the Teacher Enter the gadgets used:: Pens Pens are used by the Teacher To move ahead with code execution enter [y] else [n] y Enter your choice according to the below-listed options:: 1. To use the lru_cache() function and compare the time difference between the function with and without the lru_cache(). 2. To use the singledispatch() function and compare the time usage of the functions with and without the singledispatch(). 3. To use the reduce() function understand the various use-cases of the reduce(). 4. To use the partial() function and compare the usage of the functions with and without the partial(). 5. To exit from the code execution. 3 Enter the length of the list:: 4 87732 34853 3421 45214 entered list is [87732, 34853, 3421, 45214] Using reduce to find the sum of all the elements of the list:: The result of the sum is 171220 Using reduce to find the maximum among all the elements of the list:: Max element is 87732 To move ahead with code execution enter [y] else [n] y Enter your choice according to the below-listed options:: 1. To use the lru_cache() function and compare the time difference between the function with and without the lru_cache(). 2. To use the singledispatch() function and compare the time usage of the functions with and without the singledispatch(). 3. To use the reduce() function understand the various use-cases of the reduce(). 4. To use the partial() function and compare the usage of the functions with and without the partial(). 5. To exit from the code execution. 5 A sample program to understand the use case scenario of various functions which are offered by this Python module, in this program we have written a class in which you have separate functions out of which some of the functions or the main caller functions represent the various use case scenarios of the different functions which are provided by this Python module. these different functions are used to represent a particular use case scenario of these functions but the uses of these functions can vary according to the need or requirement of the user. the functions which are actually called to showcase the scenario actually calling the inbuilt functions of this module that actually implements the functionality of those functions Let us have a look at some of the advantages of the Functools Module in Python: Caching:Let's start with the functools module's most basic yet most powerful functions. lru cache, cache, and cached property are caching functions (and also decorators). The first is lru cache, which provides a least recently used cache of function results, or in other words, result memoization you want a bit more granular caching, you can use the typed=true argument, which caches arguments of different types individually. A function called cache is another caching decorator in functools. It's a simple wrapper on top of lru cache that omits the max size option, making it smaller and after it doesn't need to evict old data, it doesn't need to evict old values. You may also use cached property, which is another decorator for caching. This one is used for caching class attribute results, as you might expect. This is particularly beneficial if you have a property that is both expensive to compute and immutable. The advantage of the cached property is that it only executes on lookups, allowing us to change the attribute. The previously cached value will not be used after the attribute is updated; instead, a new value will be computed and cached. Clearing the cache is likewise possible; all we have to do is delete the attribute. Comparing and Ordering:You presumably already know that you can use __lt__, __gt__, or __eq__ to implement comparison operators like >=, or == in Python. It can be a pain to implement all of the __eq__, __lt__, __le__, __gt__, or __ge__ functions. Fortunately, the functools module offers the @total ordering decorator, which may assist us with this - all we have to do is implement __eq__ and one of the remaining methods, and the decorator will take care of the rest. Overloading:We were probably all taught that function overloading isn't feasible in Python, but it's actually quite simple to do so using two functions from the functools module: singledispatch and/or singledispatchmethod. These methods aid in the implementation of the Multiple Dispatch algorithm, which allows dynamically typed programming languages like Python to distinguish between types at runtime. Support for asynchronous operations:We all use a variety of external libraries and frameworks, and many of them have functions and interfaces that require us to pass in callback functions, such as asynchronous actions or event listeners. That's not new, but what if we also need to give in other arguments in addition to the callback function? This is where functools come in. partial is useful because it may be used to freeze some (or all) of the arguments of a function, resulting in a new object with a simpler function signature. We usually wish to iterate over lines when reading a file, but in the case of binary data, we might prefer to traverse over fixed-sized records instead. This may be accomplished by writing a partial callable that reads a defined chunk of data and passes it to iter, which generates an iterator from it. This iterator then executes the read method until the end of the file is reached, always accepting only the data indicated by the RECORD SIZE parameter. When the file's end is reached, the sentinel value (b") is returned, and the loop ends. Decorators:We've already discussed several decorators in prior parts, but not decorators for the purpose of constructing more decorators. functools.wraps are one such decorator. So, in this article, we have understood the Functools Module in Python. |