4

I have a function that can return one of three values: a, b, or c.

def f():
    return x # a, b, or c

I need to execute different statements based on the return value of f(): A, B, or C. The best way to do this, that I know of, is:

v = f()
if v == a:
    # Do A
elif v == b:
    # Do B
else:
    # Do C

Without introducing this new variable v, is there a different way to evaluate the return value of f()?
Something like this, maybe?

if f() == a:
    # Do A
elif _value_from_above == b:
    # Do B
else:
    # Do C
slybloty
  • 6,346
  • 6
  • 49
  • 70

3 Answers3

5

Probably not what you want, but one option is to use a dictionary of functions:

def do_a();
    ..
def do_b();
    ..
def do_c();
    ..

strategy = {
    a: do_a,
    b: do_b
    c: do_c
}

strategy[f()]()

But normally you'd want some error handling in case the dictionary entry wasn't found, in which case you'd likely end up with a separate variable anyway, plus you now have to extract each case into its own function.

Maybe even less relevant, if there are only two cases you can use a ternary operator:

do_a() if f() == a else do_b()

Though likely you already know this, plus your question has more than two cases, plus lots of people don't like the ternary operator, but anyway.

If you have a language with a switch statement, like C#/Java/C++ etc, or a pattern matching statement, like any of Haskell/OCaml/F#/Scala/Erlang etc, then you can use those. A pattern matching statement looks like this:

match f() with
| a ->
    // do something
    // and maybe something else too
| b ->
    // do some other thing
    // and yet some other thing

but there is no such feature in Python.

junichiro
  • 5,282
  • 3
  • 18
  • 26
  • An `if else` block is designed to conditionally **execute code**. The ternary operator is designed to conditionally **evaluate to a value**. I'm pretty sure the people who have issues with the ternary operator just dislike it when people use it to execute one statement or the other since that is what the `if else` statements are for. – Tadhg McDonald-Jensen Dec 15 '17 at 21:34
  • @TadhgMcDonald-Jensen you're right that the way I've used it above is awful, but lots of people seem to have a problem even when it is used to evaluate to a value. Ideally I prefer using as many pure functions as possible and only "doing" something (changing state) when absolutely necessary – junichiro Dec 15 '17 at 21:50
2

There is no way to do this with if/elif and Python does not have a switch statement. You need the temporary variable.

You can alternatively use a dispatch table if you know the exact values of a, b, and c. It's a little more verbose, but if you have a lot of possible branches, it will be faster and possibly easier to follow.

To make a dispatch table:

  • Make a function for each branch
  • Make a dictionary that maps a, b, c to their corresponding function
  • Replace all of that code with return DISPATCH_TABLE[f()]()

You can find some examples here.

Tadhg McDonald-Jensen
  • 20,699
  • 5
  • 35
  • 59
Beefster
  • 723
  • 7
  • 19
2

If you only want to map answers (without computing further), then you can solve it with a simple mapping function (similar to junichiro's answer):

import random

def f():
    foo = ['a', 'b', 'c', 'd', 'e']
    return random.choice(foo)

if __name__ == '__main__':
    from_to = dict(a=2, b=1, c=3, d=4, e=5)
    print(from_to.get(f(), None))

In case you have an unforeseen value from f() then from_to.get(f(), None) would default to None

hansaplast
  • 11,007
  • 2
  • 61
  • 75