Best method for a menu in a command line program?

Ben Finney ben+python at benfinney.id.au
Thu Nov 4 03:03:47 CET 2010


braden faulkner <brf256 at gmail.com> writes:

> I'm using a menu for my command line app using this method.
>
> choice = "foobar"

The default choice for a “nothing here yet” value is the built-in
‘None’.

Sometimes that's not the right choice; but if you have no particular
reaason in a specific program to avoid ‘None’ for that purpose, use it.

> while choice != "q":
>     if choice == "c":
>         temp = input("Celsius temperature:")
>         print "Fahrenheit:",celsius_to_fahrenheit(temp)
>     elif choice == "f":
>         temp = input("Fahrenheit temperature:")
>         print "Celsius:",fahrenheit_to_celsius(temp)
>     elif choice != "q":
>         print_options()
>     choice = raw_input("option:")

Python lacks a ‘case’ statement. But it does have functions as
first-class objects; you can treat functions as data.

So your approach above, with a chain of if-elif-elif clauses, is best
replaced by a dispatch dictionary into functions specific to each
command.

Here's my attempt at making it more Pythonic and maintainable::


    #! /usr/bin/python
    # -*- coding: utf-8 -*-

    import sys
    import textwrap

    def print_commands():
        commands_display = ", ".join(commands.keys())
        sys.stdout.write(textwrap.dedent("""\
            Valid commands are: %(commands_display)s.
            """) % vars())

    def quit():
        raise SystemExit()

    def celsius_to_fahrenheit(in_value):
        return ((in_value * (9.0/5) + 32.0))

    def fahrenheit_to_celsius(in_value):
        return ((in_value - 32.0) * (5.0/9))

    def prompt_and_convert_temperature(labels, conversion_func):
        (from_label, to_label) = labels
        input = float(raw_input("%(from_label)s: " % vars()))
        result = conversion_func(input)
        sys.stdout.write("%(to_label)s temperature: %(result)0.2f\n" % vars())

    commands = {
        'q': (lambda: quit()),
        'c': (lambda: prompt_and_convert_temperature(
                ["Celsius", "Fahrenheit"], celsius_to_fahrenheit)),
        'f': (lambda: prompt_and_convert_temperature(
                ["Fahrenheit", "Celsius"], fahrenheit_to_celsius)),
        }


    if __name__ == '__main__':
        choice = None
        while choice is None:
            choice = raw_input("Command: ")
            if choice in commands:
                commands[choice]()
            else:
                choice = None
                print_commands()

-- 
 \           “I am as agnostic about God as I am about fairies and the |
  `\           Flying Spaghetti Monster.” —Richard Dawkins, 2006-10-13 |
_o__)                                                                  |
Ben Finney



More information about the Python-list mailing list