The 9 Flavors of Callable Objects in Python

The 9 Flavors of Callable Objects in Python

Byte Sized Notes on Python Callable Objects

ยท

2 min read

In Python, a Callable is an entity that can be called similar to a function, which means the Parentheses () are used to call it too.

Different Types of Callable Objects

As of Python 3.9, there are 9 callable types:

  • User-defined Functions: Functions created with the def statement or the lambda expression.

  • Built-in Functions: Functions implemented in the Standard Python Library usually in C language.

  • Built-in Methods: Methods implemented in C language for the Standard Python Library.

  • Methods: Functions defined in the body of a class.

  • Classes: Invoking a class will make it execute its __new__ method to create an instance, then __init__ to initialize it, and eventually return the instance to the caller. Python doesn't have a new operator, so calling a class is just like calling a function.

  • Classe Instances: Classes that have a __call__ method can have their instances invoked as if they were functions.

  • Generator Functions: These are Functions or Methods that return a generator object when they use the yield keyword in their body.

  • Native coroutine functions: Functions or Methods defined with async def return a coroutine object when we call them.

  • Asynchronous generator functions: Functions or Methods defined with async def that have yield in their body, they return an asynchronous generator to use with async for.

Considering the range of callable types existing in Python, the safest way to figure out if an object is callable, we use the callable() method.

print([callable(obj) for obj in (abs, str, 'Ni!')])
# [True, True, False]

def Sample():
    return 5

test_var = Sample
print(callable(test_var))
# True

User Defined Callables

Any Object in Python can behave like a function and be called, to achieve this we need only to implement the __call__ Instance Method.

import random
class Carpool:
    def __init__(self, passengers):
        self._passengers= list(passengers)
        random.shuffle(self._passengers)

    def pick(self):
        try:
            return self._passengers.pop()
        except IndexError:
            raise LookupError('picking from empty car')

    def __call__(self):
        return self.pick()

car= Carpool(range(3))
print(car.pick())
# 1
print(Carpool())
# 0
print(callable(Carpool))
# True

Why do we need Callable Objects?

There are different situations where we might need a callable object such as:

  • Implementing __call__ in a class is an easy way to create a function-like object that has some internal state that must be kept across invocations, the example above illustrates this.

  • Decorators must be callable, and it is sometimes convenient to cache some data between calls of the decorator.

Further Reading

Did you find this article valuable?

Support Algoryst's Corner by becoming a sponsor. Any amount is appreciated!

ย