How best to write this if-else?

Andrew Dalke dalke at acm.org
Sat Apr 21 18:44:33 EDT 2001


Ben Wolfson:
>You could do
>
>def meaningful_name_1(matchobject):
>   do_complicated_processing(matchobject.group(1))
>def meaningful_name_2(matchobject): ...etc
>
>re_dispatch = {re.compile(blah):meaningful_name_1,
>               re.compile(durh):meaningful_name_2
>               ..etc
>              }
>for re, func in re_dispatch.items():
 ...

No, you wouldn't use a dictionary for that since the
order would be undefined, and this sort of situation
often has catch-all regexps which need to go after
the more specific cases.  Instead, use a list.

This has the unfortunate overhead of defining a function
for each match.  If the dispatch is supposed to modify
variables in the calling function, it isn't very useful.
In addition, one of the things the poster wanted was
the ability to 'return' inside of one of those handlers,
which you cannot do.

There are a couple of other possibilities:

matchers = (
   ("spam", re.compile("spam")),
   ("blah", re.compile("blah")),
     ...
   )

def main():
    ...
    name = None
    for name, matcher in matchers:
        m = matcher.match(line)
        if m:
            break
    if name is None:
        raise SystemExit("Game over, man")
    if name == "spam":
        text1 = m.group(1)
        do_complicated_processing (text1)
    elif name == "blah":
        text1 = m.group(1)
        text2 = m.group(2)
        print text1, text2
    elif ...

This requires using an extra name and making sure there
aren't any typos between the two names - always a problem
but should be caught during testing.

Another approach is to define a new test and store class.

class TestMatch:
    def __init__(self):
        self.match = None
    def __call__(self, pattern, line):
        self.match = pattern.match(line)
        return self.match
    def group(self, g):
        return self.match.group(g)

def main():
    ...
    test_match = TestMatch()
    if test_match(e1, line):
       text1 = test_match.group(1)
       do_complicated_processing (text1)
    elif test_match(e2, line):
       text1 = test_match.group(1)
       text2 = test_match.group(2)
       print text1, text2
    elif test_match(e3, line):
       return

This is the closest to what the original poster asked for,
but with the downsides of a more complicated system - using
a function object with side effects - and non-standard Python
code constructs.

So, ahem, "There's More Than One Way To Do It" and what you
choose should be based on what you're comfortable with.
Python isn't going to change to allow assignments in a
conditional expression so you will have to be more verbose.
But there really isn't that much verbosity.

                    Andrew
                    dalke at acm.org






More information about the Python-list mailing list