+

Functors and their use in Python

Let`s understand Functors first:

# Python code for program illustrations
# no functors

class GodClass ( object ):

  def DoSomething ( self , x):

x_first = x [ 0 ]

if type (x_first) is int :

return self .__ MergeSort (x)

  if type (x_first) is float :

return self .__ HeapSort (x)

  else :

  return self .__ QuickSort (x)

  def __ MergeSort ( self , a):

# & quot; Dummy MergeSort & quot;

print "Data is Merge sorted"

return a

def __ HeapSort ( self , b):

# & quot; Dummy HeapSort & quot;

  print "Data is Heap sorted"

retu rn b

def __ QuickSort ( self , c):

# & quot; Dummy QuickSort & quot;

print "Data is Quick sorted"

return c

# This is where custom code should know about the conditions to call another strategy
# and make it tightly coupled code.

 

godObject = GodClass ()

print (godObject.DoSomethin g ([ 1 , 2 , 3 ]))

Output:

 Data is Merge sorted [1, 2, 3] 

There are some obvious gaps in this code
1. Internal implementation must be hidden from user code, ie abstraction must be maintained.
2. Each class must handle one responsibility / functionality. 
2. The code is tightly coupled.

Let`s solve the same problem using functors in Python

# Python code for illustration programs
# using functors

 

class Functor ( object ) :

def __ init __ ( self , n = 10 ):

self . n = n

  

# This construct allows you to call objects as functions in Python

def __ call __ ( self , x):

x_first = x [ 0 ]

if type (x_first) is int :

return self . __MergeSort (x)

if type (x_first) is float :

  return self . __HeapSort (x)

else :

return self .__ QuickSort (x) 

 

def __ MergeSort ( self , a):

# & quot; Dummy MergeSort & quot;

print "Data is Merge sorted"

return a

def __ HeapSort ( self , b):

  # & quot; Dummy HeapSort & quot;

  print " Data is Heap sorted "

  return b

def __QuickSort ( self , c):

  # & quot; Dummy QuickSort & quot;

print "Data is Quick sorted"

return c

  
# Now let`s code a class that will call the above functions.
# Without a functor, this class needs to know which particular function to call
# depending on input type

 
# ## USER CODE

class Caller ( object ):

def __ init __ ( self ):

self . sort = Functor ()

 

  def Dosomething ( self , x):

# It just calls the function here and doesn`t need any care
# what sorting is used. He only knows that the sorted output will be
# the result of this call

return self . sort (x)

 

Call = Caller ()

 
# Different input data

print (Call.Dosomething ([ 5 , 4 , 6 ])) # Merge sort

  

print (Call.Dosomething ([ 2.23 , 3.45 , 5.65 ])) # heapsort

print (Call.Dosomething ([ `a` , `s` , ` b` , `q` ])) # quicksort

# Create word Vocab

Output:

 Data is Merge sorted [5, 4, 6] Data is Heap sorted [2.23, 3.45, 5.65] Data is Quick sorted [` a`, `s`,` b`, `q`] 

The above design makes it easy to change the underlying strategy or implementation without breaking any custom code. Custom code can reliably use the above functor without knowing what`s going on under the hood,
making the code separate, easily extensible and maintainable.

Now, along with functions in Python, you also understand the strategy pattern in Python, which requires separation between the class calling a specific function and the class where strategies are listed or selected.

Links:
https://www.daniweb.com/programming/software-development/threads/485098/functors-in-python

This article courtesy of Ankit Singh . If you are as Python.Engineering and would like to contribute, you can also write an article using contribute.python.engineering or by posting an article contribute @ python.engineering. See my article appearing on the Python.Engineering homepage and help other geeks.

Please post comments if you find anything wrong or if you`d like to share more information on the topic discussed above.

Get Solution for free from DataCamp guru