About   cv   Etc   Now   Zettelkästen  
Selecting user commands in style (Python)

Selecting user commands in style (Python)

This post is part of the { Programming } series.

If you write an interactive program that takes user commands as an input, you can select the appropriate action for a given command by going through a sequence of if... else if statements. But if you write in Python, there’s always a cooler way to do things. A method I like personally in this situation is defining a dictionary where the keys are the command strings, and the corresponding values are lambda expressions. In the following definition, all commands are called with command[cmd](args). When we want to deal with faulty commands immediately in a single line we can write command.get(cmd, lambda x: (error(input), help_message()))(args). By passing a command string to the dictionary as a key, the lambda expression corresponding to that command key is selected. But in order to be fully applied, the lambda function still required an argument, which we can simply pass behind the call to the dictionary. Although this method is maybe not more efficient… I would say it wins when scored on style.

def read_cmd(input):
    inputs = input.split()
    cmd = inputs[0]
    args = inputs[1:]

    commands = {
            "help": lambda x: help_message(),
            "poem": lambda x: say_poem_for(x[0]),
            "say": lambda x: banner_say(" ".join(x)),
            "exit": lambda x: banner_say("Bye cruel world!")
            }

    commands.get(cmd, lambda x: (error(input), help_message()))(args)

# Fabricate some fake user inputs for testing
user_inputs = ["Incorrect command", "say Welcome to the mean poem machine", "poem reader", "exit"]

for user_input in user_inputs:
    read_cmd(user_input)

The get function of a dictionary deals with wrong commands by returning a default value, which in our case also has to be a function, as we pass args to it. The one-liner command.get(cmd, lambda x: (error(input), help_message()))(args) therefore does the same as:

    try:
        command[cmd](args)
    except:
		error(input)
		help_message()

To run the code for yourself, you could use these silly functions. Run them in Python 3.

def help_message():
    print("""
        help        see this menu, obviously
        say         say some text placed in a ascii banner
        poem        say a little poem for your muse
        exit        say bye!
        """)


def banner_say(message):
    print("""
    xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    %s
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    """ % message)


def say_poem_for(muse):
    print("""
        Dear %s,

        Roses are not blue
        Violets are not red
        Whatever you do
        It trumps being dead
        """ % muse)


def error(incorrect_input):
    print("""
    '%s' was an example of an incorrect command
    """ % incorrect_input)

Which together produces the following output:

'Incorrect command' was an example of an incorrect command

        help        see this menu, obviously
        say         say some text placed in a ascii banner
        poem        say a little poem for your muse
        exit        say bye!
        

    xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Welcome to the mean poem machine
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    

        Dear reader,

        Roses are not blue
        Violets are not red
        Whatever you do
        It trumps being dead
        

    xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Bye cruel world!
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^