Updated On : Nov-14,2019 Tags functools, decorators, w…
functools (functions) - Generate Wrapper Functions in Python


functools module provides functions that act on other functions and returns modified functions. It lets us add more functionality by providing a wrapper around existing functions.

We'll be covering this tutorial in 2 parts. In this part, we'll be covering functions of this module and in 2nd part, we'll be covering annotations available for the same functionalities.

In [1]:
import functools
import datetime
import pytz
import time

functools functions:

  • functools.cmp_to_key(func) - It converts old-style comparison function to key function.

Comparison function takes 2 arguments and returns negative, zero and positive numbers based on less than, equal and greater than the relationship between 2 elements. The key function takes single element and returns a value that will then be used for sorting.

In [2]:
class Employee(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __str__(self):
        return self.name + ' : , Age : '+str(self.age)

e1 = Employee('Sunny',27)
e2 = Employee('Sumit',27)
e3 = Employee('Anup',35)
e4 = Employee('Ashwin',35)
e5 = Employee('Rohit',38)
e6 = Employee('Irfan',38)
e7 = Employee('Ethesh',22)
e8 = Employee('Kaushal',45)

def emp_cmp(emp1,emp2):
    return 1 if emp1.age > emp2.age else -1 if emp1.age < emp2.age else 0

sorted_employees = sorted([e8,e7,e6,e5,e4,e3,e2,e1], key = functools.cmp_to_key(emp_cmp))
print([str(emp) for emp in sorted_employees]) ## Please make a not that it's stable sort as it maintained same order for employees with same age.
['Ethesh : , Age : 22', 'Sumit : , Age : 27', 'Sunny : , Age : 27', 'Ashwin : , Age : 35', 'Anup : , Age : 35', 'Irfan : , Age : 38', 'Rohit : , Age : 38', 'Kaushal : , Age : 45']
  • functools.partial(func,*args,**kwargs) - It wraps function provided to it with arguments provided as args & kwargs set and returns partial object. It's generally used to freeze few arguments of some function with too many arguments so that one can avoid giving the same arguments again and again.
  • functools.partialmethod(func,*args,**kwargs) - It returns a new partialmethod descriptor which is the same as partial object. It's designed to be method definition in class than directly being called partial. It freezes all parameters.
In [3]:
freezed_params = {'hour':5,'minute':0,'second':59,'microsecond':999}
partial_datetime = functools.partial(datetime.datetime, **freezed_params)
partial_datetime(2015,1,1), partial_datetime(2018,2,21), partial_datetime(2017,1,31)
(datetime.datetime(2015, 1, 1, 5, 0, 59, 999),
 datetime.datetime(2018, 2, 21, 5, 0, 59, 999),
 datetime.datetime(2017, 1, 31, 5, 0, 59, 999))
In [4]:
partial_datetime.func, partial_datetime.args, partial_datetime.keywords
 {'hour': 5, 'minute': 0, 'second': 59, 'microsecond': 999})
In [5]:
class Employee(object):
    def __init__(self, name, salary):
        self.name = name
        self.salary = salary

    def decrease_salary(self, percentage):
        self.salary -= (self.salary*(percentage/100))
    def increase_salary(self, percentage):
        self.salary += (self.salary*(percentage/100))

    highest_performar_increase = functools.partialmethod(increase_salary, 30)
    average_performar_increase = functools.partialmethod(increase_salary, 15)
    bad_performar_decrease = functools.partialmethod(decrease_salary, 5)

e1 = Employee('Sumit', 25000)
e2 = Employee('Jayesh', 35000)
e3 = Employee('Rohit', 35000)
e1.highest_performar_increase(), e2.average_performar_increase(), e3.bad_performar_decrease()
e1.salary, e2.salary, e3.salary
(32500.0, 40250.0, 33250.0)
  • functools.reduce(function,iterable[,initializer]) - It applies function of 2 arguments cummunlatively to all elements of iterable from left to right to return single value.If initializer is provided then function is performed first on initializer and first element of iterable.
In [6]:
print(functools.reduce(lambda x,y : x - y, range(1,5))) # (((1-2)-3)-4)
print(functools.reduce(lambda x,y : x - y, range(1,5), 100 )) # ((((100-1)-2)-3)-4)
  • functools.update_wrapper(wrapper, wrapped, assigned=functools.WRAPPER_ASSIGNMENTS, updated=functools.WRAPPER_UPDATES) - It assigns/updates atrributes of wrapped(original function) to wrapper function.
In [7]:
(('__module__', '__name__', '__qualname__', '__doc__', '__annotations__'),
In [8]:
def outer(func):
    def inner(*args):
        print('Before execution')
        print('After execution')
    return inner

def print_title(title):
    Simple print functionality

wrapper = outer(print_title)
print('Attributes before update : '+ str(dict(zip(['__module__', '__name__', '__qualname__', '__doc__', '__annotations__','__dict__'],
                                                  [wrapper.__module__,wrapper.__name__, wrapper.__qualname__, wrapper.__doc__, wrapper.__annotations__, wrapper.__dict__]))))
functools.update_wrapper(wrapper, print_title)
print('\nAttributes after update : '+ str(dict(zip(['__module__', '__name__', '__qualname__', '__doc__', '__annotations__','__dict__'],
                                                  [wrapper.__module__,wrapper.__name__,wrapper.__qualname__, wrapper.__doc__, wrapper.__annotations__, wrapper.__dict__]))))
Attributes before update : {'__module__': '__main__', '__name__': 'inner', '__qualname__': 'outer.<locals>.inner', '__doc__': None, '__annotations__': {}, '__dict__': {}}

Attributes after update : {'__module__': '__main__', '__name__': 'print_title', '__qualname__': 'print_title', '__doc__': '\n    Simple print functionality\n    ', '__annotations__': {}, '__dict__': {'__wrapped__': <function print_title at 0x7fbb319fed90>}}
Sunny Solanki  Sunny Solanki

  Support Us

Thank You for visiting our website. If you like our work, please support us so that we can keep on creating new tutorials/blogs on interesting topics (like AI, ML, Data Science, Python, Digital Marketing, SEO, etc.) that can help people learn new things faster. You can support us by clicking on the Coffee button at the bottom right corner. We would appreciate even if you can give a thumbs-up to our article in the comments section below.

 Want to Share Your Views? Have Any Suggestions?

If you want to

  • provide some suggestions on topic
  • share your views
  • include some details in tutorial
  • suggest some new topics on which we should create tutorials/blogs
Please feel free to let us know in the comments section below (Guest Comments are allowed). We appreciate and value your feedbacks.