1

I have a function main that, given a string, should select one of many other functions, call it with some specific args and kwargs, and return its result. The most straightforward implementation of this is

def main(string):
    if string == "a1":
        return a(1)
    elif string == "a2":
        return a(2)
    elif string == "b":
        return b("foo", symbol=True)
    # ...
    elif string == "y":
        return y()

    assert string == "z", "Illegal string '{}'.".format(string)
    return z("bar", 25)

but I don't like this unsightly huge conditional. More readable is perhaps

def main(string):
    d = {
        "a1": a(1),
        "a2": a(2),
        "b": b("foo", symbol=True),
        # ...
        "z": z("bar", 25),
        }
    return d[string]

This also eliminates possible typos where a key is elif'd twice – nice. Unfortunately, this initializes every entry in the dictionary just to throw away almost all of them right away. Defining d outside of main isn't a big improvement either in my case since main is only executed a few times. Adding some lambdas works

def main(string):
    d = {
        "a1": lambda: a(1),
        "a2": lambda: a(2),
        "b": lambda: b("foo", symbol=True),
        # ...
        "z": lambda: z("bar", 25),
        }
    return d[string]()

main("a")

but again, this makes the code less readable.

I'm wondering whether it's possible to define something like a dictionary iterator: With all key-value pairs specified, but the value only evaluated when picked. Perhaps there's a better idea.

Hints?

Nico Schlömer
  • 53,797
  • 27
  • 201
  • 249
  • 1
    I don't this is a duplicate, at least not of the suggested question. The accepted answer there is exactly what OP doesn't want. – BallpointBen Jun 04 '18 at 18:35
  • 2
    I'm afraid you've got the best options already figured out. – Aran-Fey Jun 04 '18 at 18:35
  • 1
    I don't think the `lambda` is a problem, but if you do: just use a dict of tuples (a function and 0 or more arguments), then do `func, *args = d[string]` `return func(*args)`. – abarnert Jun 04 '18 at 18:35
  • @BallpointBen I think the duplicate shows that not much can be done. As Aran said, OP has already figured out what can be done. If you have a better idea I think it should go in the duplicate question. – Alex Hall Jun 04 '18 at 18:36
  • @abarnert That's certainly an option. It's gets a little more messy when kwargs are involved though (admittedly not part of the question yet -- I'll add it). – Nico Schlömer Jun 04 '18 at 18:37
  • I would also think this isn't a duplicate of the switch-question. The question here is much more specific: It's the dictionary initialization that matters here. None of the replies the in the linked question helps me out. – Nico Schlömer Jun 04 '18 at 18:39
  • 1
    I added the tuple idea as [an answer on the linked dup](https://stackoverflow.com/a/50686874/908494). Also adding `partial` in place of `lambda`. – abarnert Jun 04 '18 at 18:42
  • 1
    If you really can't stand the verbosity of `lambda` in Python (which I think is your real issue here—if you could write those functions as `\ a(1)` or something would you be complaining?), you may want to look at [MacroPy](https://github.com/lihaoyi/macropy), which includes macros for shorter lambdas, two kinds of case statements, and all kinds of other things, as well as a framework to write your own. I probably wouldn't use it for production code, but it is a lot of fun to play with… – abarnert Jun 04 '18 at 18:46
  • 1
    None of the duplicated answers are helping because there is no perfect solution to this problem. If you find an ideal solution to your question here, it will also solve the switch question, and vice versa. – Alex Hall Jun 04 '18 at 18:48
  • 1
    I've added [this answer](https://stackoverflow.com/a/50688208/2482744) which is about as concise as it can get. – Alex Hall Jun 04 '18 at 20:25

0 Answers0