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.