Python multimethods using isinstance

740 views Asked by At

In this article Guido van Rossum says that this kind of multimethod implementation in Python:

def foo(a, b):
    if isinstance(a, int) and isinstance(b, int):
        ...code for two ints...
    elif isinstance(a, float) and isinstance(b, float):
        ...code for two floats...
    elif isinstance(a, str) and isinstance(b, str):
        ...code for two strings...
    else:
        raise TypeError("unsupported argument types (%s, %s)" % (type(a), type(b)))

is "tedious" and "not very OO". He then goes into a description of how decorators may be used to implement multimethods which I would think would be inaccessible to those without a rather deep knowledge of Python.

My question: I need to write a multimethod, what is actually "not OO" about the code above?

UPDATE: In light of Thomas Orozco's answer, I now realise I don't actually "need" to write a multimethod at all.

1

There are 1 answers

1
Thomas Orozco On BEST ANSWER

Rather than inspecting the types of the objects that are being passed to your method, you would make it so that the objects implement the logic themselves.

Lets take an example: the len function.

A native implementation would be:

def len(x):
    if type(x) == str:
        # compute the length of a string
    elif type(x) == list:
        # compute the length of a list
    else:
        #

But this has a few caveats

  • You couldn't support len in your own objects without re-implementing len
  • It's a huge, unreadable, mess

And, most importantly, the OO-part about it, it means that your implementation of str is scattered across your codebase: the code for computing its length is here, the code for slicing it is somewhere else...


Instead, a much saner design is what's used in Python:

def len(x):
    return x.__len__()

It's then up to each object to implement the __len__ method itself. The len function just asks the object for its length.

To a certain extent, you can consider this a "Strategy Pattern"