16

I have a Python program that takes user input. I store user input a string variable called "userInput". I want to be able to call the string the user entered...

userInput = input("Enter a command: ")
userInput()

From this, I get the error: TypeError: 'str' object is not callable

Currently, I have the program doing something like this:

userInput = input("Enter a command: ")
if userInput == 'example_command':
    example_command()

def example_command():
     print('Hello World!')

Clearly this isn't a very efficient way to process a lot of commands. I want to make the str obj callable - anyway to do so?

just_a_programmer
  • 341
  • 1
  • 3
  • 9
  • 7
    I think the thing you are looking for is eval('string'). Make sure that you do heavy checking on what that string is though because otherwise you will have some major security issues. You will also have to add "()" to the end of the input string. – Evan Apr 20 '14 at 01:07
  • 3
    @Evan even *with* heavy checking, running eval on user input is probably not good idea. The check you would want to do is "is this string one of the approved set", at which point you might as well do a dict lookup. – lvc Apr 20 '14 at 01:31
  • @Evan just curious, what does eval() do & why does it cause security issues? – just_a_programmer Apr 20 '14 at 03:10
  • 2
    It attempts to run a string. If a hacker wants to get into your system, it makes it insanely easy. They just have to know what functions to call and what variables you have. Then they just go on their merry way. Example, if you had a linked list with some variable "size", the could call eval, I think exec too, "my_list.size = 0" and change the size. More on these at [python docs](https://docs.python.org/release/3.2.3/library/functions.html?highlight=eval#eval) – Evan Apr 20 '14 at 03:16

2 Answers2

32

A better method might be to use a dict:

def command1():
    pass

def command2():
    pass

commands = {
    'command1': command1,
    'command2': command2
}

user_input = input("Enter a command: ")
if user_input in commands:
    func = commands[user_input]
    func()

    # You could also shorten this to:
    # commands[user_input]()
else:
    print("Command not found.")

Essentially, you're providing a mapping between the literal command, and the function you might want to run.

If that's too much typing, you could also use the local keywords, which will return a dictionary of every function, variable, etc. currently defined within the current scope:

def command1():
    pass

def command2():
    pass

user_input = input("Enter a command: ")
if user_input in locals():
    func = locals()[user_input]
    func()

This isn't entirely secure though, because a malicious user could enter a command which is the same as a variable name, or some function you don't want them to run, and end up crashing your code.

Michael0x2a
  • 58,192
  • 30
  • 175
  • 224
1

You could do it with the exec method .
Basically the exec command executes strings.

user_input = input()        # example command
exec(user_input + '()')     # append the function parenthesis

You have to keep in mind that it is dangerous to allow users to execute code without proper validation.

Jitin
  • 346
  • 3
  • 13