For example, if I have a function called add
like
def add(x,y):
return x+y
and I want the ability to convert a string or a
[I got here via a duplicate question. My first thought was to use argparse
and shlex
and I didn't see that here, so I'm adding it as another option.]
You could use argparse
to set up a registry of functions/commands and safely parse their args. This will provide some level of user-friendliness too by, e.g., letting you know when you've entered a command that doesn't exist.
import argparse
import shlex
def hello(name):
print('hello,', name)
def main():
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers()
hello_parser = subparsers.add_parser('hello')
hello_parser.add_argument('name')
hello_parser.set_defaults(func=hello)
print('Enter q to quit')
while True:
command = input('command> ')
command = command.strip()
if not command:
continue
if command.lower() == 'q':
break
words = shlex.split(command)
try:
args = parser.parse_args(words)
except SystemExit:
# argparse will sys.exit() on -h and errors; prevent that
continue
func_args = {name: value for name, value in vars(args).items()}
del func_args['func']
args.func(**func_args)
if __name__ == '__main__':
try:
main()
except KeyboardInterrupt:
print()
The built-in function eval will do what you want. All the usual warnings about executing arbitrary user-supplied code apply.
If there are a finite number of predefined functions, you should avoid eval
and use a lookup table instead (i.e. Dict
). Never trust your users.
Since you are taking user input, the safest way is to define exactly what is valid input:
dispatcher={'add':add}
w='add'
try:
function=dispatcher[w]
except KeyError:
raise ValueError('invalid input')
If you want to evaluate strings like 'add(3,4)'
, you could use safe eval:
eval('add(3,4)',{'__builtins__':None},dispatcher)
eval
in general could be dangerous when applied to user input. The above is safer since __builtins__
is disabled and locals
is restricted to dispatcher
. Someone cleverer than I might be able to still cause trouble, but I couldn't tell you how to do it.
WARNING: Even eval(..., {'__builtins__':None}, dispatcher)
is unsafe to be applied to user input. A malicious user could run arbitrary functions on your machine if given the opportunity to have his string evaluated by eval
.