def function1(arguments):
print("Function 1",arguments)
def function2(arguments):
print("Function 2",arguments)
userInput = input()
Is it possible for the user to enter a function and arguments and for said function to run. eg the user enters function2("Hello World")
Though you can always use eval to make this work but for reasons eval is evil, it is better to use a dictionary call back mechanism, notably
You can create a dictionary to bind the function with the names and call them with appropriate parameters
call_backs = {'function1': function1, 'function2': function2}
assuming you provide an input as follows function2, "Hello World",
You first need to split the data userInput = userInput .split(',') and pass it onto the callback function via the dictionary
call_backs[userInput[0]](userInput[1])
Related
How can I add something to a list outside of a function:
greeting = ["Hello","Hi"]
def addGreeting():
greeting.append(raw_input("add greeting here: "))
How can I change the actual value of a list/variable outside of a function inside a function?
First off, the code you posted works as intended:
greeting = ["Hello","Hi"]
print(greeting)
def addGreeting():
greeting.append(raw_input("add greeting here: "))
addGreeting()
print(greeting)
Whatever you added will indeed be in greeting. But this is very messy and implicit, and it relies on the specific names you've given variables. Instead, consider doing
def add_greeting_from_input(greetings):
greetings.append(raw_input("add greeting here: "))
return greetings
Now this function is much more flexible and is totally unambiguous about what it acts on. Functions that have implicit behavior should ideally be confined to classes, where they obviously (hopefully) act on the instance itself.
greeting = ["Hello", "Hi"]
Design a function that takes in parameters to replace with arguments when run.
def addGreeting(list,newgreeting):
list.append(newgreeting)
Now call the function
addGreeting(greeting,"This is a new greeting!")
I am still working on the same encryption program before and I am currently stuck.
choice = ""
def program (str,my_fn):
global i
i=0
while i<len(str):
my_fn
i += 1
def encrypt(my_result):
message.append(ord(answer[i]))
while choice != "Exit":
choice = input("Do you want to Encrypt, Decrypt, or Exit?\n")
if choice == "Encrypt":
answer = input("What would you like to encrypt:\n")
message = []
program(answer,encrypt(message))
print (answer)
print (message)
So the first part of the program is simply asking the user if they wish to Encrypt, Decrypt, or Exit the program, this part works perfectly fine. However, my issue is with the functions. Function "program" is intended to serve as a repeater for the inner function for every single letter in the string. However, when I try to run the program, it continues to tell me that "i" isn't defined for the "encrypt" function and does nothing. I am certain I set "i" as a global variable so why isn't this working. In case you are wondering why I chose to make two functions, it is because I will later have to use function "program" multiple time and for this specific assignment I am required to use functions and abstractions. Thanks!
Add one line after your first line
choice = ""
i = 0
The keyword global means you declare an access to a global name.
Also, using a global variable is almost never a good idea. You may want to find another way to design your function.
The line program(answer,encrypt(message)) doesn't do what you want it to do. Rather than passing the function encrypt and its argument message to program (which can call it later), it calls the function immediately. It would pass the return value to program instead, but since encrypt(message) doesn't work without i defined, you get an exception instead.
There are a few ways you could fix this. By far the best approach is to not use global variables in your functions, and instead always pass the objects you care about as arguments or return values.
For instance, you could pass a function that encrypts a single letter to another function that repeatedly applies the first one to a string (this would be very much like the builtin map function):
def my_map(function, string):
result = []
for character in string:
result.append(function(character))
return result
def my_encryption_func(character):
return ord(character)
If you really want to stick with your current architecture, you could make it work by using functools.partial to bind the answer argument to your encrypt function, and then call the partial object in program:
from functools import partial
def program (str,my_fn):
global i
i=0
while i<len(str):
my_fn() # call the passed "function"
i += 1
def encrypt(my_result):
message.append(ord(answer[i]))
choice = ""
while choice != "Exit":
choice = input("Do you want to Encrypt, Decrypt, or Exit?\n")
if choice == "Encrypt":
answer = input("What would you like to encrypt:\n")
message = []
program(answer, partial(encrypt, message)) # pass a partial object here!
print (answer)
print (message)
I would like to call a function from a user input, but include arguments in the parenthesis. For example, if I have a function that takes one argument:
def var(value):
print(value)
I would like to ask the user for a command and arguments, then call the function with the arguments:
Input Command: var("Test")
Test
Split the function name from the arguments. Look up the function by name using a predefined map. Parse the arguments with literal_eval. Call the function with the arguments.
available = {}
def register_func(f):
available[f.__name__] = f
#register_func
def var(value):
print(value)
from ast import literal_eval
def do_user_func(user_input):
name, args = user_input.split('(', 1)
return available[name](*literal_eval('(' + args[:-1] + ',)'))
do_user_func("var('test')") # prints "test"
This is still incredibly brittle, any invalid input will fail (such as forgetting parentheses, or an invalid function name). It's up to you to make this more robust.
literal_eval is still somewhat unsafe on untrusted input, as it's possible to construct small strings that evaluate to large amounts of memory. '[' * 10 + ']' * 10, for a safe but demonstrative example.
Finally, do not use eval on untrusted user input. There is no practical way to secure it from malicious input. While it will evaluate the nice input you expect, it will also evaluate code that, for example, will delete all your files.
Any attempt to make eval safe will end up being more complex than any of the solutions here, for no practical benefit. It will still not be safe in some way you didn't anticipate. Don't do it.
I am going to post this solution as an alternative, under the assumption that you are dealing with simple inputs such as:
var(arg)
Or, a single function call that can take a list of positional arguments.
By using eval it would be a horrible un-recommended idea, as already mentioned. I think that is the security risk you were reading about.
The ideal way to perform this approach is to have a dictionary, mapping the string to the method you want to execute.
Furthermore, you can consider an alternative way to do this. Have a space separated input to know how to call your function with arguments. Consider an input like this:
"var arg1 arg2"
So when you input that:
call = input().split()
You will now have:
['var', 'arg1', 'arg2']
You can now consider your first argument the function, and everything else the arguments you are passing to the function. So, as a functional example:
def var(some_arg, other_arg):
print(some_arg)
print(other_arg)
d = {"var": var}
call = input().split()
d[call[0]](*call[1:])
Demo:
var foo bar
foo
bar
You should investigate the cmd module. This allows you to parse input similar to shell commands, but I believe you can get tricky and change the delimiters if the parentheses are an important part of the specification.
Instead of using eval, you can parse it yourself. This way, you have control over how each function should parse/deserialize the user input's arguments.
import sys, re
def custom_print(value):
print value
def custom_add(addends):
print sum(addends)
def deserialize_print(args):
# just print it as is
custom_print(args)
def deserialize_add(args):
# remove all whitespace, split on commas, parse as floats
addends = [float(x) for x in re.sub(r"\s", "", args).split(",")]
# send to custom_add function
custom_add(addends)
def get_command():
cmd_input = raw_input("Command: ")
# -- check that the command is formatted properly
# and capture command groups
match = re.match(r"^([a-zA-Z0-9]+)(\(.*\))?$", cmd_input)
if match:
# extract matched groups to separate variables
(cmd, argstring) = match.groups()
# strip parenthesis off of argstring
if argstring:
args = argstring[1:-1]
# send the whole argument string to its corresponding function
if cmd == "print":
deserialize_print(args)
elif cmd == "add":
deserialize_add(args)
elif cmd == "exit":
sys.exit()
else:
print "Command doesn't exist."
else:
print "Invalid command."
# recurse until exit
get_command()
# -- begin fetching commands
get_command()
This is a pretty rough setup, although you can get by with some more error checking and improving the deserializing functions and modularizing function additions.
If the decoupled deserialize functions seem too much, you can also just move the deserialization into the custom functions themselves.
Following is an example of function called from user-input, using Class:
class Wash:
def __init__(self, amount):
self.amount = amount
if amount == 12:
print("Platinum Wash")
elif amount == 6:
print("Basic Wash")
else:
print("Sorry!")
amount = int(input("Enter amount: "))
payment = Wash(amount)
I'm trying to do something like this for a project:
def printhi():
print("Hi")
myinput = input() # for example printhi()
exec(myinput)
Now I get an error, because exec() just starts a new session and ignores my functions and variables. How can I change that?
The exec builtin takes two additional arguments that can be used to pass in the local and global scope:
x = 10
exec("print(x)", globals(), locals()) # Prints "10"
Update: Given your example, I think a "better" solution (or at least something more realistic) is to not use exec. To call a function given by the user, try something like:
mypinput = input()
choices = {'printhi': printhi}
if myinput in choices:
function = choices[myinput]
function()
else:
print("Unknown function", myinput)
I have a list of tuples consisting of name, phone number and address, and a function called "all" which just shows a list of all the tuples (like in a phonebook). The function is called via input from a user.
I want another function, called "entry" which shows a specific entry of my list. This function should be called via input as well with the index number of the entry (for example, "entry 12") and show just this entry.
Although I can't figure out how to take the number from the input as a parameter for my function and how to call the function. Does it have to contain a variable in the function name which will later be replaced by the number? How can i do that?
Have you looked into argparse?
import argparse
parser = argparse.ArgumentParser(description='your description')
parser.add_argument('-entry', dest="entry")
args = parser.parse_args()
print (args.entry)
You can then call this with python yourfile.py -entry="this is the entry"
That will allow you to take an input when you run the file.
I'm sorry if misunderstood your question, but it seems like you need function arguments. For example: if your `entry' program just prints out what the user put in, your code would look like this:
def entry(user_input): # the variable in the parentheses is your argument--is a local variable ONLY used in the function
print user_input # prints the variable
# now to call the function--use a variable or input() as the function argument
entry(input("Please input the entry number\n >>> ") # see how the return from the input() function call is used as a variable? this basically uses what the user types in as a function argument.
Try running it, and you'll see how it works.
Best of luck and happy coding!