Kodeclik Logo

Our Programs

Courses

Gifting

Learn More

Schedule

Kodeclik Blog

What are functors in Python?

In functional programming, functors are objects that can be treated and used as though they are functions. They provide a way to encapsulate behavior and allow us to apply functions in a flexible and compositional manner. Let's dive deeper into the concept of functors as objects that behave like functions.

In functional programming, the term "functor" refers to objects that can be called as if they were functions. They encapsulate a callable entity, such as a function, and provide additional context or state. This allows us to treat them like functions and apply them in various scenarios.

In Python, functors are typically implemented using classes that define the __call__ method. Remember that a class is like a blueprint that defines how an object should behave. So, a functor class specifies what should happen when the functor is called.

In more detail, the __call__ method allows instances of the class to be invoked as if they were functions. When an instance of a functor class is called, it triggers the execution of the __call__ method, just like invoking a regular function.

Let's create a simple functor together. Imagine you have a class called DoubleFunctor that is intended to double any number you give it. Here's how it looks:

class DoubleFunctor:
  def __call__(self, number):
      return number * 2

In the code above, we define a class called DoubleFunctor. Inside this class, we have a special method called __call__. This method is what gets triggered when we call the functor.

Here is how we use our DoubleFunctor:

my_daily_double = DoubleFunctor()
result = my_daily_double(5)
print(result)

The output will be:

10

What is the big deal you might ask? The first point to note is that even though “DoubleFunctor” has a “return number * 2” line, it doesn’t quite return the double of a number. Rather, it returns a function that returns the double of a number. Notice the higher level of abstraction. Then when we define my_daily_double, that is the real function that will return the double of a number.

We can make this more complicated and update our program as follows:

class MultiplyFunctor:
    def __init__(self, factor):
        self.factor = factor
    def __call__(self, number):
        return number * self.factor

multiply_by_ten = MultiplyFunctor(10)
result = multiply_by_ten(5)
print(result) 

multiply_by_six = MultiplyFunctor(6)
result = multiply_by_six(5)
print(result)

Note the more complicated functor definition above. In the code above, we define a class called MultiplyFunctor that takes an argument called factor in its constructor. That information is later used in the __call__ method to perform the multiplication of number by the factor. Note that in the previous code, we only had the __call__ method because the factor was implicit.

After the functor is defined,note that we create two instances of MultiplyFunctor – multiply_by_ten with a factor of 10 and multiply_by_six with a factor of 6. We then call each instance as if it were a function, passing a number as an argument. The functor multiplies the number by the specified factor, returning the result. The output is thus:

50
30

as expected.

By using the MultiplyFunctor class, we can easily create custom multiplication functions with different factors, allowing for flexible and reusable code.

Here is a more elaborate example where we are defining a functor to count the number of characters in a string. There are many ways to count characters, e.g., count all characters, count only vowels, count only non-vowels, i.e., consonants, and so on. Below is a functor definition to support all of them:

class LengthFunctor:
  def __init__(self, mode="characters"):
      self.mode = mode


def __call__(self, string):
    if self.mode == "characters":
        return len(string)
    elif self.mode == "vowels":
        return sum(1 for char in string if char.lower() in "aeiou")
    elif self.mode == "consonants":
        return sum(1 for char in string 
          if char.isalpha() and char.lower() not in "aeiou")

In this code, we define the LengthFunctor class that takes an optional argument called mode. The mode determines how the length of the string will be calculated. The __call__ method is implemented to perform the length calculation based on the specified mode.

We can use this functor repeatedly as follows by developing functions and applying them to the string “Kodeclik”:

Functors in Python
usualcounter = LengthFunctor("characters")
print(usualcounter("Kodeclik"))

vowelcounter = LengthFunctor("vowels")
print(vowelcounter("Kodeclik"))

consonantcounter = LengthFunctor("consonants")
print(consonantcounter("Kodeclik"))

The output will be:

8
3
5

as expected since there are 8 total characters, with 3 vowels and 5 consonants in “Kodeclik”.

Note that because of the default setting we use the first use of LengthFunctor could have been declared as just:

usualcounter = LengthFunctor()
print(usualcounter("Kodeclik"))

and this would have given the same output as before.

As you can see from the above examples, functors provide you a higher level of abstraction. They enable you to hide the details and give rise to clean code. They also have several practical applications in programming.

For instance, functors are often used for mapping and transforming data. By defining a functor that represents a specific transformation, we can apply it to different elements in a collection. This allows us to perform consistent and reusable transformations.

Functors are also commonly used as callback functions. In event-driven programming or asynchronous operations, callbacks are functions that are executed when certain events occur or when a task is completed. Functors provide a convenient way to define these callbacks and pass them as arguments to other functions.

We hope you enjoyed learning about functors. If you liked this, learn more about Python lambda functions which will help you become a better functional programmer.

Interested in more things Python? Checkout our post on Python queues. Also see our blogpost on Python's enumerate() capability. Also if you like Python+math content, see our blogpost on Magic Squares. Finally, master the Python print function!

Want to learn Python with us? Sign up for 1:1 or small group classes.

Kodeclik sidebar newsletter

Join our mailing list

Subscribe to get updates about our classes, camps, coupons, and more.

About

Kodeclik is an online coding academy for kids and teens to learn real world programming. Kids are introduced to coding in a fun and exciting way and are challeged to higher levels with engaging, high quality content.

Copyright @ Kodeclik 2024. All rights reserved.