Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Method overloading for different argument type in python

I'm writing a preprocessor in python, part of which works with an AST.

There is a render() method that takes care of converting various statements to source code.

Now, I have it like this (shortened):

def render(self, s):
    """ Render a statement by type. """

    # code block (used in structures)
    if isinstance(s, S_Block):
        # delegate to private method that does the work
        return self._render_block(s)

    # empty statement
    if isinstance(s, S_Empty):
        return self._render_empty(s)

    # a function declaration
    if isinstance(s, S_Function):
        return self._render_function(s)

    # ...

As you can see, it's tedious, prone to errors and the code is quite long (I have many more kinds of statements).

The ideal solution would be (in Java syntax):

String render(S_Block s)
{
    // render block
}

String render(S_Empty s)
{
    // render empty statement
}

String render(S_Function s)
{
    // render function statement
}

// ...

Of course, python can't do this, because it has dynamic typing. When I searched for how to mimick method overloading, all answers just said "You don't want to do that in python". I guess that is true in some cases, but here kwargs is really not useful at all.

How would I do this in python, without the hideous kilometre-long sequence if type checking ifs, as shown above? Also, preferably a "pythonic" way to do so?

Note: There can be multiple "Renderer" implementations, which render the statements in different manners. I can't therefore move the rendering code to the statements and just call s.render(). It must be done in the renderer class.

(I've found some interesting "visitor" code, but I'm not sure if it's really the thing I want).

like image 435
MightyPork Avatar asked Aug 16 '14 21:08

MightyPork


People also ask

Can method overloading have different data types?

No, you cannot overload a method based on different return type but same argument type and number in java. same name. different parameters (different type or, different number or both).

Can you do method overloading in Python?

Function overloading is also called method overloading. The method of calling the same method in different ways is called method overloading. Unlike other programming languages, python does not support method overloading by default.

Why does Python not support method overloading?

Why no Function Overloading in Python? Python does not support function overloading. When we define multiple functions with the same name, the later one always overrides the prior and thus, in the namespace, there will always be a single entry against each function name.

What is method overloading example in Python?

Method overloading example. We create a class with one method sayHello(). The first parameter of this method is set to None, this gives us the option to call it with or without a parameter. An object is created based on the class, and we call its method using zero and one parameter.

How to overload a method in Python?

Like other languages (for example method overloading in C++) do, python does not supports method overloading. We may overload the methods but can only use the latest defined method. # First product method.

Is there a possible duplicate of overloaded functions in Python?

possible duplicate of Overloaded functions in python? It's method overloading, not method overriding. And in Python, you historically do it all in one function: class A: def stackoverflow (self, i='some_default_value'): print 'only method' ob=A () ob.stackoverflow (2) ob.stackoverflow ()

What is method overloading in C++?

Method Overloading: 1 Method Overloading is the class having methods that are the same name with different arguments. 2 Arguments different will be based on a number of arguments and types of arguments. 3 It is used in a single class. 4 It is also used to write the code clarity as well as reduce complexity.

What is the difference between overload and Lambda in Python?

overload takes any amount of callables and stores them in tuple functions, then returns lambda. The lambda takes any amount of arguments, then returns result of calling function stored in functions [number_of_unnamed_args_passed] called with arguments passed to the lambda.


2 Answers

Would something like this work?

self.map = {             S_Block : self._render_block,             S_Empty : self._render_empty,             S_Function: self._render_function } def render(self, s):     return self.map[type(s)](s) 

Keeping a reference to a class object as a key in a dictionary and having it's value be the function object you want to call will make your code shorter and less error prone. The only place an error could occur here would be in the definition of the dictionary. Or one of your internal functions of course.

like image 193
rocktheartsm4l Avatar answered Oct 04 '22 21:10

rocktheartsm4l


If you're using Python 3.4 (or are willing to install the backport for Python 2.6+), you can use functools.singledispatch for this*:

from functools import singledispatch

class S_Block(object): pass
class S_Empty(object): pass
class S_Function(object): pass


class Test(object):
    def __init__(self):
        self.render = singledispatch(self.render)
        self.render.register(S_Block, self._render_block)
        self.render.register(S_Empty, self._render_empty)
        self.render.register(S_Function, self._render_function)

    def render(self, s):
        raise TypeError("This type isn't supported: {}".format(type(s)))

    def _render_block(self, s):
        print("render block")

    def _render_empty(self, s):
        print("render empty")

    def _render_function(self, s):
        print("render function")


if __name__ == "__main__":
    t = Test()
    b = S_Block()
    f = S_Function()
    e = S_Empty()
    t.render(b)
    t.render(f)
    t.render(e)

Output:

render block
render function
render empty

*Code based on this gist.

like image 39
dano Avatar answered Oct 04 '22 22:10

dano