2 min read

Multiple dispatch in python

Multiple dispatch in python

“It would be cool to have the same function name, but to have different code executed depending on what is passed to the function!” - I know many people who ask this question when they work with Selenium in python. It’s a typical situation when you have a function that should behave differently in different situations. But at the same time, the meaning of the function does not change, so creating another function with a similar name is not exactly what you want.

For example, you have a wrapper function that searches for an element of a page. You can pass a locator and a Webdriver object into that function or you can pass a locator and an element object. In the first case, you need to find an element using a Webdriver object and perform some actions like waiting, scrolling, etc. In the second case, you already have the element object and you need to search for a new element inside the existing one.

You can do it by using if/else statements, but also this becomes possible with the multipledispatch library. Let's look at it in more detail.

How to install it?

Installation is very simple:

pip install multipledispatch

Where to read more about it?

You can find the source code on GitHub and also you can find some information in the official documentation.

Some examples

Let me show you some examples so you could see the benefits of using this library.

Let's say we have some function that should change its behaviour depending on the type of incoming data. Instead of having a bunch of if/else statements in the function itself, you can split this function into several with the same name, and specify types that the function should handle:

from multipledispatch import dispatch
 
@dispatch(int)
def test_function(num):
    print(f'{num} - Integer!')
 
 
@dispatch(str)
def test_function(message):
    print(f'{message} - String!')

If we call this function with different values, we’ll get different outputs depending on the type:

test_function(5)
# 5 - Integer!
 
test_function('word')
# word - String!

How about other types?

This library is not limited to simple types like int, float, str, etc., you can also check for Iterator, Number, class instances and a whole lot more. It is also possible to pass several values.

Example with classes

Here is an example of using this library with a class. First, let's define 2 classes:

class OneClass:
    def print_value(self, value):
        print(f'{value} - class one')
 
class TwoClass:
    def print_value(self, value):
        print(f'{value} - class two')

Then let’s write some functions which will get our classes as an argument:

from multipledispatch import dispatch

@dispatch(OneClass, int)
def test_function(obj: OneClass, num):
    obj.print_value(num)
    print('Integer!')

@dispatch(TwoClass, str)
def test_function(obj: TwoClass, message):
    obj.print_value(message)
    print('String!')

Now let’s create objects of these classes and try to call our functions:

one = OneClass()
two = TwoClass()

test_function(one, 5)
# 5 - class one
# Integer!

test_function(two, 'word')
# word - class two
# String!

Again, you can see different outputs depending on the arguments we pass to the function.

Conclusion

If you face a situation where you need to change the function behaviour depending on arguments, this library might help you very much. I hope that now you have another possible tool to make your code better!

Do you use this library in your project? Please, share your experience with me!