Making Objects Callable
00:00 Normally, when you create an object from a class you interact with it by calling its methods like some object dot some method. But what if you could use your object just like a function?
00:13 That’s where being callable comes into play. What is a callable object again? A callable is any object that you can call using a pair of parentheses and optionally a series of arguments.
00:26
You’ve been using them all the time. For example, functions, classes, and methods. To make your own you can add the .__call__() special method to your class.
00:41
Any instance of a class with a .__call__() method behaves like a function.
00:48
To see how this works in practice, let’s create a Factorial class that caches already computed values for efficiency. This will help you understand how callables work in Python.
01:00
In this example, you’ll implement the call magic method because you want to make the Factorial class itself callable. This means that instead of using a method like factorial.calculate(), you’ll be able to directly call the class instance with a number like factorial(5) or factorial(4).
01:21
Let’s see how that goes. Okay, let’s start by defining the class. So class Factorial:. Then you need to set up the class with an .__init__() method that initializes a a cache dictionary.
01:36
This will store the results of factorials you’ve already calculated so you don’t have to calculate them again. def __init__(self): and let’s call it self.cache = {} because you want a dictionary.
01:55
Now comes the key part, the __call__ magic method. By defining this method, you are making the Factorial class callable. So this means that you use an instance of Factorial just like you’d use a function. self and n.
02:15
Now you have to check if the factorial of n that you’re calculating has already been calculated or not. If it is, you just return it right away without the need to actually recalculate it.
02:34
you simply return self.cache [n], and if the factorial isn’t cached, you calculate it. For zero and one the factorial is one, for any other number you calculate it by multiplying n by the factorial of n - 1 so you create a recursion.
02:57
After computing the result, you store it in the cache and then return it. So let’s do that. if n == 0 or n == 1, the result would be just 1.
03:13
Anything else result would be n * the factorial or self of (n - 1).
03:26
After that, you have to store this result in your cash dictionary. So self.cache[n] equals the result you just calculated, and finally, you just return this result
03:42
and that’s the entire logic that you needed. But to just make this better, let’s create a developer-friendly string representation by using the .__repr__() magic method that you explored earlier.
03:56
This would show what’s currently in the cache. def __repr__(self):
04:05
You’re returning first the class name, so Factorial,
04:10
and then you’re saying this is the cache. So cache = {self.cache}.
04:20
And that’s about it. Now let’s create an instance of the Factorial class. So factorial = Factorial() factorial class with the parentheses, so you’re calling it, and then let’s print, for example, the factorial of five.
04:40
So factorial(5), let’s see what we get.
04:46
And you get 120. So this works. There you go. The __call__ method has made the factorial class itself callable. Instead of writing something like factorial.calculate() or factorial.compute(5), you can simply write factorial(5).
Become a Member to join the conversation.
