8

Alright, so my title sucked. An example works better:

input = 'check yahoo.com'

I want to parse input, using the first word as the "command", and the rest of the string as a parameter. Here's the simple version of how my non-Pythonic mind is coding it:

if len(input) > 0:
    a = input.split(' ')
    if a[0] == 'check':
        if len(a) > 1:
            do_check(a[1])
    elif a[0] == 'search':
        if len(a) > 1:
            do_search(a[1])

I like Python because it makes normally complicated things into rather simple things. I'm not too experienced with it, and I am fairly sure there's a much better way to do these things... some way more pythonic. I've seen some examples of people replacing switch statements with dicts and lambda functions, while other people simply recommended if..else nests.

Tom
  • 681
  • 8
  • 14
  • A previous python-switch question: http://stackoverflow.com/questions/60208/replacements-for-switch-statement-in-python – monkut Mar 13 '09 at 04:52
  • For interest's sake also you might want to check out an old (it has been rejected) Python Enhancement Proposal (PEP) that was put together for including a switch statement in Python: http://www.python.org/dev/peps/pep-3103/ – Wayne Koorts Apr 16 '09 at 02:19

6 Answers6

31
dispatch = {
  'check': do_check,
  'search': do_search,
}
cmd, _, arg = input.partition(' ')
if cmd in dispatch:
    dispatch[cmd](arg)
else:
    do_default(cmd, arg)
Markus Jarderot
  • 86,735
  • 21
  • 136
  • 138
4

I am fairly sure there's a much better way to do these things... some way more pythonic.

Not really. You code is simple, clear, obvious and English-like.

I've seen some examples of people replacing switch statements with dicts and lambda functions,

Yes, you've seen them and they're not clear, obvious or English-like. They exist because some people like to wring their hands over the switch statement.

while other people simply recommended if..else nests.

Correct. They work. They're simple, clear, ...

Your code is good. Leave it alone. Move on.

Frank Krueger
  • 69,552
  • 46
  • 163
  • 208
S.Lott
  • 384,516
  • 81
  • 508
  • 779
3

This lets you avoid giving each command name twice; function names are used almost directly as command names.

class CommandFunctions:
    def c_check(self, arg):
        print "checking", arg

    def c_search(self, arg):
        print "searching for", arg

    def c_compare(self, arg1, arg2):
        print "comparing", arg1, "with", arg2

    def execute(self, line):
        words = line.split(' ')
        fn = getattr(self, 'c_' + words[0], None)
        if fn is None:
            import sys
            sys.stderr.write('error: no such command "%s"\n' % words[0])
            return
        fn(*words[1:])

cf = CommandFunctions()
import sys
for line in sys.stdin:
    cf.execute(line.strip())
rob mayoff
  • 375,296
  • 67
  • 796
  • 848
  • This can even be better by using an error handling method as the default value for gettr (instead of None), so you don't have to check for unknown commmands explicitly – Ber Mar 13 '09 at 10:04
  • I thought about doing that, but the called function doesn't get words[0] so it would not be able to print the unknown command in the error message. – rob mayoff Mar 31 '09 at 07:00
0

If you're looking for a one liner 'pythonic' approach to this you can use this:


def do_check(x): print 'checking for:', x
def do_search(x): print 'searching for:', x

input = 'check yahoo.com'
{'check': do_check}.get(input.split()[0], do_search)(input.split()[1])
# checking for: yahoo.com

input = 'search google.com'
{'check': do_check}.get(input.split()[0], do_search)(input.split()[1])
# searching for: google.com

input = 'foo bar.com'
{'check': do_check}.get(input.split()[0], do_search)(input.split()[1])
# searching for: bar.com
adam
  • 6,582
  • 4
  • 29
  • 28
  • Well, it certainly doesn't simplify Tom's example, but it takes his 8 lines of code and does the same thing in just one line. – adam Mar 13 '09 at 05:33
  • on second glace, he used an elif. I had initially thought he used an else. I need to revise my code. Sorry for the confusion. – adam Mar 13 '09 at 05:35
  • dude this is so wrong. your dictionary only has "check", as if one would need a dictionary to choose between "check" and "search" because an "if" statement is not sufficient! – hasen Mar 13 '09 at 08:56
  • This is way too complicated. If I see this code I would certainly pull my hair out. It's just an "if elif" construct for god sake. – miya Mar 13 '09 at 13:56
  • hey, it's not that bad! You can extend the dictionary with as many commands as you like, leaving one default (probably not do_search, but some error handler) in {}.get() - and it's still more compact than if-elif-elif-....-else construct. – Abgan Mar 13 '09 at 17:59
0

Disregard, I just realized that my answer was similar to one of the other answers - and apparently there's no delete key :)

John C
  • 6,285
  • 12
  • 45
  • 69
0

Variation on @MizardX's answer:

from collections import defaultdict

dispatch = defaultdict(do_default, check=do_check, search=do_search)
cmd, _, arg = input.partition(' ')
dispatch[cmd](arg)
Community
  • 1
  • 1
jfs
  • 399,953
  • 195
  • 994
  • 1,670