Python informer

Improve your Python coding skills

Callable objects

A callable object is an object that can be used like a function. That is, it can be invoked, ie “called”, using brackets (). It can also be passed in wherever a callable object is required, for example in a map function.

Normal Python functions are one example of callable objects. You can also make your won callable object by implementing the __call__ method.

Example LinePrinter class

Here is a simple class that performs a similar job to print, except that it adds an incrementing line number before each print:

class LinePrinter:  

    def __init__(self):
        self.line = 0

    def print(self, x):
        print(self.line, x)
        self.line += 1

printn = LinePrinter()
printn.print("a")
printn.print("b")

This creates the following output:

0 a
1 b

Making the object callable

This works fine, but it might be even better if instead of writing printn.print() we could just use printn(). We can do this by defining a method __call__:

class LinePrinter:  

    def __init__(self):
        self.line = 0

    def __call__(self, x):
        print(self.line, x)
        self.line += 1

printn = LinePrinter()
printn("a")
printn("b")

Apart from being neater, this approach has the advantage that we can also use the object printn as if it were a function object. For example, with map:

list(map(printn, [10, 20, 30]))

Note that map is a lazy function, it will not execute printn until it needs to. By creating a list of the map we force it to evaluate, and therefore to print the output. The result is:

0 10
1 20
2 30

Changing the signature

You can give the __call__ method any signature you wish. The object will behave like a function of the required signature (excluding the hidden self parameter):

class LinePrinter:  

    def __init__(self):
        self.line = 0

    def __call__(self, *args, **kwargs):
        print(self.line, *args, **kwargs)
        self.line += 1

printn = LinePrinter()
printn("a", "b", "c")
printn(10, 20, 30, sep='-')

In this case we have allowed the function to accept *args and **kwargs, that is a variable number of unnamed and named parameters. These are passed on to the print function. This means that we can pass through multiple values per line, and also named parameters such as sep (one of the standard print parameters). The result is:

0 a b c
1-10-20-30

Notice that the sep parameter is passed to print to control the character between values, setting it to - rather than space.

Closures

For the sake of simplicity, this example is a little contrived. There are other ways to solve the same problem. In this case a closure would provide the same functionality, but in a way that is arguably a little simpler. Here is the code:

def LinePrinter():  
    line = 0

    def fn(*args, **kwargs):
        nonlocal line
        print(line, *args, **kwargs)
        line += 1
        
    return fn

printn = LinePrinter()
printn("a", "b", "c")
printn(10, 20, 30, sep='-')

Here, rather than creating a class, we have created a LinePrinter function (the outer function). That function has a variable line and an inner function fn (that corresponds to the __call__ method). The outer function, when called, returns an object of the inner function.

The fun part about closures is that the inner function object can still access it’s own private copy of the line variable! So each time the function is called it will increment the count.

In reality, for problems such as this you would most likely use a closure rather than creating your own callable object. Firstly because it is simpler and secondly because it is the standard way to solve this type of problem. If you do things in a non-standard way, anyone reading your code will be scratching their head trying to figure out why you didn’t just use a closure.