Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Executing functions within switch dictionary

I have encountered a problem when putting all the modules I've developed into the main program. The switch dictionary I've created can be seen below:

def Tank_Shape_Calcs(Tank_Shape, level, area, dish, radius, length, Strapping_Table, Tank_Number):

    switcher = {
        0: vertical.Vertical_Tank(level, area),
        1: horiz.Horiz_Cylinder_Dished_Ends(dish, radius, level, length),
        2: strapping.Calc_Strapped_Volume(Strapping_Table, level),
        3: poly.Fifth_Poly_Calcs(Tank_Number)
    }
    return switcher.get(Tank_Shape, "ERROR: Tank type not valid")

The tank shape is set in the main file in a loop for each of the tanks. The first tank has Tank_Shape = 2 so I would expect it to execute the Calc_Strapped_Volume() function.

I have tried testing it, and the switcher function is definitely reading Tank_Shape as 2. Also if I change the functions to strings, it will print out the correct string.

The problem is that the functions seem to be executed sequentially, until the correct function is called. This results in errors as the data I'm using will only work with the correct function.

Is there a way to only execute the correct function?

like image 738
J.Greenslade Avatar asked Jan 17 '17 13:01

J.Greenslade


People also ask

How do you call a function in switcher Python?

There is a dictionary switcher which helps on mapping to the right function based on the input to the function Choice . There is default case to be implemented which is done using switcher. get(i, 'Invalid') , so if this returns 'Invalid' , you can give an error message to user or neglect it.

Can we store function in dictionary?

Given a dictionary, assign its keys as function calls. Case 1 : Without Params. The way that is employed to achieve this task is that, function name is kept as dictionary values, and while calling with keys, brackets '()' are added.

Can Python dictionary contain functions?

Python dictionary contains multiple keys This method is a in-built function in Python and it returns true if all the elements of dict1 are contained in original dictionary.


3 Answers

All your functions are executed when you build the dictionary, not when you access the key.

You need to use lambda (without any parameters, they are already known) to make sure the function is only called when required:

switcher = {     0: lambda : vertical.Vertical_Tank(level, area),     1: lambda : horiz.Horiz_Cylinder_Dished_Ends(dish, radius, level, length),     2: lambda : strapping.Calc_Strapped_Volume(Strapping_Table, level),     3: lambda : poly.Fifth_Poly_Calcs(Tank_Number) } 

then call when you return, with the error message as a lambda that returns it:

return switcher.get(Tank_Shape, lambda : "ERROR: Tank type not valid")() 
like image 152
Jean-François Fabre Avatar answered Sep 20 '22 09:09

Jean-François Fabre


As noted, the functions will get invoked during dictionary construction. Besides that, there's two other issues I see here:

  • Redefining switcher during every invocation of the function Tank_Shape_Calcs, this generally isn't a good idea.
  • Requiring all arguments to be passed (due to their definition as positionals) when only a handful of them might be needed, this is why we have *args :-)

If my understanding of what you're up to is correct, I'd move switcher outside the function, as a Tank_Shape to function object mapping:

switcher = {     0: vertical.Vertical_Tank,     1: horiz.Horiz_Cylinder_Dished_Ends,     2: strapping.Calc_Strapped_Volume,     3: poly.Fifth_Poly_Calcs } 

Then, define Tank_Shape_Calcs to take the excess arguments as a tuple with *args:

def Tank_Shape_Calcs(Tank_Shape, *args):     return switcher.get(Tank_Shape, lambda *_: "ERROR: Tank type not valid")(*args) 

and invoke your function after .getting it.

This also plays off Jean's trick to define a lambda in .get but does so with *_ in order to allow it to get called with many args (which are consequently ignored).

like image 27
Dimitris Fasarakis Hilliard Avatar answered Sep 21 '22 09:09

Dimitris Fasarakis Hilliard


What you are doing in your code, is creating a dictionary with integer keys (0-3) and function results as values. Hence, you first call all the functions and then access the return values of these functions. I would change your code as following:

def Tank_Shape_Calcs(Tank_Shape, level, area, dish, radius, length, Strapping_Table, Tank_Number):
    switcher = {
        0: (vertical.Vertical_Tank, (level, area)),
        1: (horiz.Horiz_Cylinder_Dished_Ends, (dish, radius, level, length)),
        2: (strapping.Calc_Strapped_Volume, (Strapping_Table, level)),
        3: (poly.Fifth_Poly_Calcs, (Tank_Number,))
    }
    func, args = switcher.get(Tank_Shape, (None, None))
    if func is not None: 
        return func(*args)

Here, you get first the function you want to call with the according arguments and call it.

like image 36
BloodyD Avatar answered Sep 20 '22 09:09

BloodyD