Dante
Dante

Reputation: 17

Pass argument to function that is stored as a value in a dictionary

I am making a virtual terminal for a basic hacking game. Commands need to be given by user. Commands are stored as a dictionary, like the following

commandslist = {"systemtime": systemtime(),
            "ping": ping(),
            "pwd": pwd(),
            "ifconfig": ifconfig(),
            "help": helpmenu(),
            "shop": shop()}

That references the actual functions

def ifconfig():
    ipaddr = user["ipaddr"]
    return ipaddr
def ping(ip4="127.0.0.1"):
    if ip4 in enemyuser["ipaddr"]:
        x = "64 bytes from " + ip4 +": icmp_seq=1"
    else:
        x ="No ping response"
    return x

The code in main.py reads for user input and for loops to find it. I dont want a bunch of messy if statements

while 1:
userinput = input(bash)
if " " in userinput:
    command, options = userinput.split(" ")
else: 
    command = userinput
for i in commandslist:
    if i == command:
        print(commandslist[i])

Basically I need to pass the ip address of enemy computer to the ping command but I can't figure out a way if I could update the ping() call in the dictionary to include the options that would be good

Upvotes: 0

Views: 47

Answers (1)

Carcigenicate
Carcigenicate

Reputation: 45736

First, this isn't directly the problem you're asking about, but {"systemtime": systemtime()} calls the systemtime function when the dictionary is created, not when the "systemtime" key is accessed! This means all your functions will run immediately at the start, then never again. You can fix this by storing the functions, without calling them:

commandslist = {"systemtime": systemtime,
                "ping": ping,
                "pwd": pwd,
                "ifconfig": ifconfig,
                "help": helpmenu,
                "shop": shop}

I mention this because once you've made that fix, this is a lot easier to solve (and, it's far more correct).

First, I'd modify the line that cuts up the user input, since it's a little off as well for more complicated cases:

 command, *options = userinput.split(" ")

Note the *. This will collect every element after the first into options. That means if the user enters somecommand arg1 arg2 arg3, options will hold (arg1, arg2, arg3).

After that runs, use command to do a lookup to fetch the chosen function:

func = commandslist[command]

Then apply the options arguments to the function:

func(*options)

*options expands the sequence of options they gave into the argument list of the func function.

Something like:

userinput = input(bash)
command, *options = userinput.split(" ")
func = commandlist[command]
print(func(*options))

Also, the whole

for i in commandslist:
    if i == command:

part doesn't make sense if you think about it. You're checking for i to be equal to command. But if they're equal, why not just use command directly like I'm showing? Yours will silently fail if they enter a bad command, when you likely want to actual show an error to them.

Also note, you'll want to do error handling, or do an if command in commandslist check ahead of time. If the user enters a not existent key, or the wrong number of arguments, this will crash. You'll want to catch the KeyError, and the TypeError from the wrong number of arguments.

Upvotes: 2

Related Questions