0

I have a function that checks 3 different boolean flags and has a unique outcome for each of the 8 combinations.

""" a | b | c | out - + - + - + --- 0 | 0 | 0 | 0 0 | 0 | 1 | 1 0 | 1 | 0 | 2 0 | 1 | 1 | 3 1 | 0 | 0 | 4 1 | 0 | 1 | 5 1 | 1 | 0 | 6 1 | 1 | 1 | 7 """ def do_stuff(a, b, c): if a: if b: if c: return function7() # a, b, c return function6() # a, b, !c if c: return function5() # a, !b, c return function4() # a, !b, !c else: if b: if c: return function3() # !a, b, c return function2() # !a, b, !c if c: return function1() # !a, !b, c return function0() # !a, !b, !c 

I'm already short-cutting a lot of else statements since I'm returning (exiting the loop).

Is there a more DRY way to accomplish this? I could convert to binary, and do a single depth level of if/elif, but I don't want to use "magic numbers".

Also, I realize this is only 16 lines of code for 8 outcomes, but what if it were 4 variables, is there a way to increase readability/flow?

5
  • 4
    Why not just a mapping {0: function0, ...}, etc.? Commented Dec 2, 2015 at 21:08
  • What do the functions do? Commented Dec 2, 2015 at 21:08
  • @ReutSharabani the functions call a redirect to unique Django views Commented Dec 2, 2015 at 21:23
  • do you really need 8 views? are they that different? This seems like not the best deaign. I could be wrong though. Commented Dec 2, 2015 at 21:25
  • @ReutSharabani well, it maybe could be a little more concise, but it's not within the scope to rewrite the underlying functions. Basically this function processes a user submitted web form and generates a pdf. So the various booleans change a print template, filter by a customer, and filter past due. Regardless of the actual use case, it peeked my curiosity about ways to process multiple bools Commented Dec 2, 2015 at 21:29

3 Answers 3

4

You need to have some sort of mapping from outcome to function and a mapping from input to outcome. The nifty table you provide at the top, combined with the fact that bools in Python are just the integers 0 and 1 gives you the following:

outcomeToFunc { 0: function0, 1: function1, 2: function2, 3: function3, 4: function4 # etc... } def inputToOutcome(a, b, c): return a << 2 | b << 1 | c def do_stuff(a, b, c): outcome = inputToOutcome(a, b, c) return outcomeToFunc[outcome]() 

If you are interested in having an arbitrary number of boolean inputs, you can modify do_stuff and inputToOutcome to use varargs:

outcomeToFunc { 0: function0, 1: function1, 2: function2, 3: function3, 4: function4 # etc... } def inputToOutcome(*args): outcome = 0 n = len(args) - 1 for ind, arg in enumerate(args): outcome |= bool(arg) << (n - ind) return outcome def do_stuff(*args): outcome = inputToOutcome(*args) try: return outcomeToFunc[outcome]() except KeyError: raise ValueError('Outcome {} not supported'.format(outcome)) 
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks. That table just screams bit ops to me.
1

Here are two solutions. It is up to you to decide if they are prettier than the one you presented.

def do_stuff(a, b, c): flags = bool(a), bool(b), bool(c) if flags == (True, True, True): return function7() if flags == (True, True, False): return function6() if flags == (True, False, True): return function5() if flags == (True, False, False): return function4() if flags == (False, True, True): return function3() if flags == (False, True, False): return function2() if flags == (False, False, True): return function1() if flags == (False, False, False): return function0() def do_stuff(a, b, c): control = { (True, True, True): function7, (True, True, False): function6, (True, False, True): function5, (True, False, False): function4, (False, True, True): function3, (False, True, False): function2, (False, False, True): function1, (False, False, False): function0, } return control[bool(a), bool(b), bool(c)]() 

Comments

-2

First you can build a binary to decimal converter.After obtaining the new number you can call the method by function name in an string by eval function:

def function0(): print("function0") def function1(): return 1; a = eval("function1()") print(a) 

Remember that you can pass global variables to eval function unless the current global names id used.

3 Comments

The "main tip" is a bad idea.
@jonrsharpe. Agreed. We want all the tips.
While this works, it seems the least desireable solution.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.