Python Functools Module
Overview
The functools module is part of Python's standard library and was implemented for higher-order functions. Higher-order functions are those functions that either accept a function as an input or return another function as an output. For example, map(), filter(), etc. are the higher order functions. Functools is one of the most useful standard libraries of Python which consists of a collection of higher order functions.
Python Functools Module
As mentioned above, the python functools module provides essential functionality for working with the higher order functions. And the functools in python provide many such higher order functions that are mentioned below:
- reduce()
- wraps()
- lru_cache()
- cached_property()
- partial()
- update_wrapper()
- singledispatchmethod()
- singledispatch()
- cmp_to_key()
- total_ordering()
- partialmethod()
Classes in Python Functools Module
The python functools module has two classes namely, partial class and partialmethod class. A higher order function called partial allows for the partial application of a function whereas the partialmethod class is only a method descriptor and it isn’t callable but it returns a new partialmethod descriptor.
Partial class
As mentioned above, with the help of the partial class, you can create partial objects, and hence it allows the partial application of the function. Let’s take an example to understand the partial class in python. Suppose you have a function that contains more than one argument. Now, the situation is you need to change only some of the arguments and not all, every time you use that function. In this case, Python’s partial class can be very handy. Here, using the partial class you can fix any number of arguments and you don’t have to create another function to achieve this.
Syntax:
- partial.func
- The partial.func returns the name of parent function with hexadecimal address.
- partial.args
- The partial.args returns the positional arguments provided in the partial function.
- partial.keywords
- The partial.keywords returns the keyword arguments provided in the partial function.
Now, let’s take an example to understand the partial class in Python.
In the below example, you need to display all the texts with having “text” message type along with the message itself. But as you can see you have call the function messenger and in every call, you have to specify the type of message i.e. “text” along with the value of the message. That means every function call takes 2 arguments i.e. type and message.
Example:
Output:
Now, the other way around it is that using a partial function from the python functools module. Using the partial function you can fix the value of the type argument to TEXT and a new function can be created i.e. text_messenger which accepts only one argument that is message and returns the same result as the above example.
Example:
Output:
Partialmethod
The function partialmethod() returns partialmethod descriptors. It's comparable to the partial() function for methods, if that helps. This indicates that its primary purpose is to define new methods rather than to be callable. Let's first see the syntax of the partialmethod and then we'll discuss with an example that's given in the Python official documentation.
Syntax:
Example:
Output:
In the above example, we've defined a class of the name Cell that represents a single cell. The class Cell has a single property that is alive and an instance method of the name set_state() which sets the alive property to either False or True. After this, we've created two partialmethod descriptors. These descriptors i.e. set_alive() and set_dead() calls the set_state() method with the states as True or False respectively. These descriptors will help us to create a new instance of the class Cell as mentioned in the above example and then we eventually calls the set_alive() descriptor to change the state of the cell (here aCell) to True. At last the value of this property is printed in the above example which shows True as an output.
Functions and methods in Python Functools Module
-
**reduce(): ** The reduce() function in Python performs functional computation by taking a function and an iterable (e.g., tuple, list, dictionary, etc.) as inputs, and returning the result after computation i.e. after the process of applying the function on the given iterable. The reduce() function in python is defined in the functools module and it just returns a single value as output which is the result of the whole iterable which gets reduced to only a single integer or a boolean or a string.
Syntax:
Here, the reduce function has two arguments,
- function: The first argument is a function. Generally, it’s a lambda function. It is applied to all the elements in an iterable.
- iterable: It is an iterable object, for example, a list, dictionary, tuple, etc.
-
lru_cache(): lru_cache() is a decorator which is used in reducing the function execution for the same inputs using a technique called Memoization. Memoization is a caching technique that assures that a function does not have to be run multiple times for the same inputs. Instead, the function's output is saved in memory the first time it is called and can be retrieved later if necessary.
LRU Cache stands for Least-Recently-Used Cache, which refers to a cache that drops the least recently used element if the maximum size of entries is reached.
Syntax
Here, the decorator has two parameters:
- max_size: The max_size parameters specify how many entries the cache may hold before evicting old items. If the value of maxsize is set to none, the cache will grow indefinitely and hence this will lead to many problems if more entries are cached.
- typed: It is a boolean parameter. If set to true the cache indicates that the cache will have varied entries for different types of function arguments.
-
singledispatch(): The other higher order function is singledispatch(). This decorator i.e. singledispatch() transforms any function into a single-dispatch function that too a generic function. In simple words, singledispatch() allows you to overload functions in Python. The overloading with the help of the singledispatch was recently introduced in the Python 3.4. Let's take an example to understand the singledispatch() decorator. Example:
In the above example, the singledispatch decorator is used to dispatch the add function. Note that as shown in the example the singledispatch happens only on the first argument type. First, we've imported the singledispatch function from the Python functools module. A function of the name add is created and this will be called only if all the other decorated functions cannot handle the type of the arguments passed.
As shown in the above example, first we have passed the two int arguments to the add function and we got the final result after addition of the two elements. But when again two arguments were passed of the type str and int, we got the TypeError stating that the operand is not supported for 'int' and 'str'.
- wraps():
@wraps is a decorator that uses update_wrapper() as a convenience function. It is equivalent to executing partial(update_wrapper, wrapped=wrapped, assigned=assigned, updated=updated), to be exact.
Let's take an example from the Python's official documentation to understand the wraps(). Example:
Output:
When defining a wrapper function, wraps acts as a function decorator by taking in the function it is wrapping. The characteristics of the wrapper function are changed to match those of the wrapped function. The metadata for the wrapper function would be returned rather than the original function's metadata or attributes, which are meant to represent the true metadata for the entire function, if this update was not supplied to the wrapper function using wraps(). Wraps() are incredibly helpful in preventing these kinds of bug-ridden programs.
- cmp_to_key():
Let’s first understand the difference between the key function and a comparison function.
Any callable that accepts two arguments, compares them, and then outputs a result based on the arguments' input order is a comparison function. The first argument is more than the second argument if the first argument is negative, zero if the first and second arguments are equal, and if the first argument is greater than the second, then it will be a positive value.
A key function is a callable that accepts one argument and returns another value to be used as the sort key.
A cmp_to_key() function changes a comparison function into a key function. In python 2 there existed a function called cmp() for comparisons and ordering. The cmp_to_key() function was implemented to support the transition from Python 2 to 3.
- total_ordering():
When you want to accomplish a task of an object comparison you can use the total_ordering() decorator. You can define the methods like __eq__(), __lt__(), __le__(), __gt__(), __ge()__ which implies to (==, <, <=, >, >=).
You don't have to define all the methods when using the total_ordering() decorator and it becomes quite tedious to do so. But, Python is smart enough that you only have to define two methods i.e. __eq__() and the one from the remaining rest of the methods.
Uses of Python Functools Module
There are different use cases of the Python functools module and it depends on the use of the higher order functions. As discusses above in the article, there are different higher order functions in the python functools module and you can use these functions in various cases as mentioned below:
- The partial class is provided by the functools module and with the help of the partial class, you can create partial objects, and hence it allows the partial application of the function. Whenever you need to have an application of partial objects you can use the partial class from the python functools module.
- Similar to partial class there is another class named partialmethod. The function partialmethod() returns partialmethod descriptors. The usage of the partialmethod and its primary purpose is to define new methods rather than to be callable.
- The reduce() function in python functols module is widely used and it just returns a single value as output which is the result of the whole iterable which gets reduced to only a single integer or a boolean or a string.
- If you want to reduce the function execution then you can use the lru cache() higher order function from the python functools module. lru_cache() is a decorator which is used in reducing the function execution for the same inputs using a technique called Memoization.
- You can also overload functions in the Python which was introduced recently. The singledispatch() from the python functools allows you to overload functions in Python.
There are many such use cases of the Python functools module or we can say higher order functions defined in the python functools module has such wide use cases which can be used according to the requirements.
Advantages of Python Functools Module
-
Caching: The most basic, yet powerful, features of the functools module i.e. caching. Caching functions include lru cache, cache, and cached property (and also decorators). The lru_cache() offers a cache of the most recently used function results, or it can be said memoization. The typed=true parameter allows for more precise caching by storing arguments of various kinds separately.
-
Overloading: Although function overloading in Python was undoubtedly taught to all of us as being impossible, it is actually rather easy to do so utilizing two functions from the functools module: singledispatch and/or singledispatchmethod. These techniques support the Multiple Dispatch algorithm's implementations, which enables dynamically typed programming languages like Python to differentiate between types in real time.
-
Comparing and Ordering: You probably already know that you can build Python comparison operators like >=, or == using __lt__(), __gt__(), or __eq__(). Implementing all of the __eq__(), __lt__(), __le__(), __gt__(), or __ge__() functions might be difficult. Thankfully, the @total_ordering decorator provided by the functools module may be of use to us in this endeavor. All we need to do is implement __eq__() and one of the remaining methods, and the decorator will take care of the rest.
-
Asynchronous Operations Support:
-
There are number of external libraries and frameworks, and many of them have functions and interfaces that require us to send in callback functions, such event listeners or asynchronous actions. That's nothing new, but what if we additionally need to supply more arguments to the callback function? Here, functools can be really an ideal use case. A function's arguments can be frozen using partial, creating a new object with a more straightforward function.
-
Decorators: The @wraps is used for the purpose of constructing more decorators as discussed in this article.
Examples for Understanding
Below are the examples of the python functools’ higher order functions as discussed above.
Example:
In the above example that is referenced from the Python official documentation, a DataSet instance is holding a (big) sequence of numbers. Additionally, two techniques are provided for computing variance and standard deviation, respectively. We make both functions cached properties by applying the @cached property decorator to them. This indicates that the value is, in fact, only computed once before being cached.
Example:
Output:
In the above example, the partial function is used to create a partial application of the object as mentioned in the above example.
Example:
In the above example, a class of the name Being is defined. It has a property i.e. alive and a method i.e. set_state_of_being() which sets the alive to True or False. And, there are two partialmethod descriptors i.e. set_alive() and set_dead() which calls the set_state_of_being() with True or False respectively.
Example:
In the above example, a list is defined which contains numbers. The reduce() function is used and we’ll calculate the multiplication by calling the reduce() function with the operator.mul() function as the first argument and the given list as the second argument.
Example:
Output:
As shown in the above example, the percentages of the Students are compared using the Python functools module and the total_ordering() decorator. As discussed in the total_ordering() section, you do not need to define all the methods to compare the objects. Just define the __eq__() and one from the lists mentioned above and Python will figure out what should be the output in the different remaining cases.
FAQs
Q: What is Python functools module?
A: The python functools module provides essential functionality for working with the higher order functions. And the functools module in python provide many such higher order functions like, reduce(), lru_cache(), partial(), cmp_to_key(), etc.
Q: Are there any advantages of using the Python functools module?
A: Yes, there are many advantages of using the Python functools module. The most basic, yet powerful, features of the functools module i.e. caching. Another advantages of using the Python functools module are Asynchronous Operations Support, decorators using @wraps , and you can also accomplish the task of compairing and ordering.
Conclusion
- The functools module is part of Python's standard library and was implemented for higher-order functions.
- Higher-order functions are those functions that either accept a function as an input or return another function as an output. For example, map(), filter(), etc.
- The functools in python provide many such higher order functions such as: partial(), update_wrapper(), singledispatchmethod(), singledispatch(), cmp_to_key(), total_ordering(), etc.
- A higher order function called partial allows for the partial application of a function whereas the partialmethod class is only a method descriptor and it isn’t callable but it returns a new partialmethod descriptor.
- The reduce() function in Python performs functional computation by taking a function and an iterable (e.g., tuple, list, dictionary, etc.) as inputs, and returning the result after computation.
- lru_cache() is a decorator which is used in reducing the function execution for the same inputs using a technique called Memoization.