In Python want to use user input as function call [duplicate] - python

This question already has answers here:
Calling a function of a module by using its name (a string)
(18 answers)
Is there a way to store a function in a list or dictionary so that when the index (or key) is called it fires off the stored function?
(3 answers)
Closed 5 months ago.
In Python I want to use user input as a function call. In particular, I have the following code I'm testing out:
def forward(forwardValue):
print("in forward, with value " + forwardValue)
return
command = 'forward' # this would come in as user input
value = '255'
command(value)
What I would like to see is a printout that says: in forward, with value 255
What I do see is an error that:
'str' object is not callable
That error message makes sense, and I can see why what I tested doesn't work, but is there any way to do what I want to do? In other words, can user input be used as a function call?
What I do currently instead is use an "if" statement to check if the user input is the 'forward' statement, and if so to call the function 'forward'. But I would like to be more Pythonesque if possible.
I have a list of about 30 different commands the user can use, each of which commands has a defined function to handle it. My series of 30 "if" and "elif" statements seems clumsy.

Quick and dirty solution
Use globals():
globals()[command](value)
Wiser approach
However, if security is a concern, you may want to limit what can be called from user input. For example define a dictionary of callable functions:
functions = {'forward': forward, 'othercommand': othercommand}
or combine with previous solution to avoid repetitions:
functions = {k: globals()[k] for k in ('forward', 'othercommand')}
Then you would call your function with:
functions[command](value)
Alternative approach
You can use a class as namespace for your user-callable functions:
class Functions:
#staticmethod
def forward(arg):
print("in forward, with value " + forwardValue)
#staticmethod
def othercommand():
pass
(if you are on Python 3.x, #staticmethod is optional in this context)
then access the static methods with getattr():
getattr(Functions, command)(value)

Daanii, what seems to be catching you is that the variable named command contains the string 'forward'. This string object is not your function. Using an if statement, as you said you are already doing, is the most straightforward way to go about it.
If you have many functions and/or you don't necessarily want the function name and the user-passed string to match, then I would suggest using a dictionary.
d = {'foward':forward, 'backward':backward, 'flurb':durf}
def forward(forwardValue):
print("in forward, with value " + forwardValue)
return
def backward(backwardValue):
print("in backward, with value " + backwardValue)
return
def durf(value):
print("in durf, with value " + value)
return
try:
command = raw_input('Enter your thing:\n')
value = '255'
d[command](value)
except KeyError:
print 'The user did not enter a valid string'

Related

I solve a code in Coursera using this method and it worked but they didn't accept it? [duplicate]

This question already has answers here:
What is the formal difference between "print" and "return"? [duplicate]
(6 answers)
Closed 6 months ago.
Modify the student_grade function using the format method, so that it returns the phrase "X received Y% on the exam". For example, student_grade("Reed", 80) should return "Reed received 80% on the exam".
I solve this code just like this and I got the result but Coursera shows that is wrong answer why?
def student_grade(name, grade):
print("{name} received {grade}% on the exam".format(name=name,grade=grade))
return ""
Here is your output:
Reed received 80% on the exam
Paige received 92% on the exam
Jesse received 85% on the exam
Not quite. Check that you're filling in the contents of the
student_grade function as requested.
TL;DR: The question is asking you to return the string. What you are doing is printing it. Instead, do this:
def student_grade(name, grade):
return "{name} received {grade}% on the exam".format(name=name,grade=grade)
In order to pass values to functions, we use arguments. But what if we want to pass values back? Say we make a function, add(). It takes two numbers and wants to give the calling code their sum. If it just prints the result, the code that calls the function can't get it; printing is just a way of displaying things to the user.
That's where returns come in. A return value is what the calling code gets when it calls the function. To return in Python, we use the return statement. A kind of common misconception is that return itself is a function, and you need to put parentheses aroundt he value being returned. That is not the case. Thus, instead of printing the value, you should just return it, like so:
def student_grade(name, grade):
return "{name} received {grade}% on the exam".format(name=name,grade=grade)
Then the calling code can do things with the return value, like store it in a variable:
grade = student_grade("Mark", 97)
And later, if it wants to, output it:
print(grade)

How to dynamically access a class and its methods from an input? [duplicate]

This question already has answers here:
How to get class object from class name string in the same module?
(3 answers)
Closed last year.
I am creating a python CLI, where user can provide an operation they want to perform, for eg:
sum 10 15
In my code, I have defined my classes as follows:
class Operation:
# common stuff
pass
class Sum(Operation):
identifier = "sum"
def perform(a, b):
return a + b
class Difference(Operation):
identifier = "diff"
def perform(a, b):
return a - b
Now, in my CLI, if I type sum 10 15 I want to return the result of Sum.perform(10, 15) and similarly if I type diff 10 15, I return the result of Difference.perform(10, 15), as sum is the identifier of class Sum and diff is the identifier of class Difference.
How do I dynamically access the class and its perform method, when I get the input directly from user input?
Classes in Python are first-class citizens, meaning they can be used as standard objects. In particular we can simply store them in a dictionary:
my_dict = {
'sum': Sum,
'diff': Difference,
}
and so on. Then when you get the operation name as string from command line you simply do
my_dict[op_name].perform(a, b)
Note that this is a very basic (and you will soon see problematic, e.g. not all operators accept two arguments) approach to what is known as parsing and abstract syntax trees. This is a huge topic, a bit hard but also very interesting. I encourage you to read about it.
// EDIT: If you want to keep identifier on the class, then you can apply a simple class decorator:
my_dict = {}
def autoregister(cls):
# It would be good idea to check whether we
# overwrite an entry here, to avoid errors.
my_dict[cls.identifier] = cls
return cls
#autoregister
class Sum(Operation):
identifier = "sum"
def perform(a, b):
return a + b
print(my_dict)
You have to remember though to import all classes before you use my_dict. In my opinion an explicit dict is easier to maintain.
Reading your comment, I think you need to interpret the input. The way I would go about this is splitting the input by spaces (based on your example), and then checking that list. For example:
# This is the place you called the input:
input_unsplit = input("Enter your command and args")
input_list = input_unsplit.split(" ")
# Check the first word to see what function we're calling
if("sum") in input_list[0].lower():
result = Sum.perform(input_list[1], input_list[2])
print(result)
# this logic can be applied to other functions as well.
This is a simple solution that could be hard to scale.
=== EDITED ===
I have more to add.
If used correctly, dir() can make a list of defined classes up to a certain point in the code. I wrote a calculator for my precal class, and in it I chose to use dir after defining all the math classes, and then if the name met certain conditions (i.e not main), it would be appended to a list of valid args to pass. You can modify your classes to include some kind of operator name property:
def class Addition:
self.op_name = "sum"
and then perform to take in an array:
def perform(numbers):
return numbers[0] + numbers [1]
To solve many of your scalability issues. Then, after declaring your classes, use dir() in a for loop to append to that valid array, like so:
valid_names = []
defined_names = dir()
for name in defined_names:
if '_' not in name:
if name not in ("sys","argparse","<any other imported module/defined var>"):
valid_names.append(name)
Note that making this step work for you is all in the placement in the script. it's a bit tedious, but works flawlessly if handled correctly (in my experience).
Then, you can use eval (safe in this context) to call the method you want:
# get input here
for name in defined_names:
if eval(name).op_name == input_list[0].lower():
eval(name).perform(input_list)
This should be a fairly easy-to-scale solution. Just watch that you keep the dir check up to date, and everything else just... works.

How can I call a function with a string? [duplicate]

This question already has answers here:
Calling a function of a module by using its name (a string)
(18 answers)
Closed 2 years ago.
I have used the following code:
from time import time
import datetime
now = datetime.datetime.now()
Report = now.strftime("%Y%m%d_%H%M%S") + "Prueba llamada de funciones" + ".txt"
modo=0
def llamar_funciones():
if (modo==1):
Alimentaciones_1(Report)
Alimentaciones_2(Report)
else:
print("¿Que ensayos de alimentaciones quieres hacer?")
Ensayo=input()
Nombre_Ensayo= "Alimentaciones_" + Ensayo
print(Nombre_Ensayo)
Nombre_Ensayo(Report)
def Alimentaciones_1(Report):
f = open(Report,"a")
f.write("1.funtzioa")
f.close()
def Alimentaciones_2(Report):
f = open(Report,"a")
f.write("\n2.funtzioa")
f.close()
llamar_funciones()
I get the following error:
TypeError: 'str' object is not callable
How can I call the function 1 or 2 depending on the value of the variable "modo"??
You simply need another if statement. You can't call strings, but you can branch based on them.
if Ensayo == "1":
Alimentaciones_1(Report)
elif Ensayo == "2":
Alimentaciones_2(Report)
else:
# ... Handle invalid user input here ...
For what it's worth, you can call a function whose name is a string, but it's poor coding style and extremely bug-prone. To be clear, the following is for educational purposes; do not do it. The above snippet is the accepted way to do this sort of thing.
eval("Alimentaciones_{}".format(Ensayo))(Report) # <-- Bad idea
Python has two functions that might help you, exec() and eval().
They both take a string and treat it like python code (you could use the string from the input and run it), and behave slightly differently.
However, and this is important, don't use them. At all. Those functions are extremely dangerous, as they let the user call every function from your code if they wish, and it's bad practice.
I recommend to use if cases to check for the values you want like:
if my_str == "my_func":
my_func(...)
elif my_str == "my_other_func":
my_other_func(...)
...
This might be tedious but it will let your users call whatever they need to and not more.

Parentheses in Python's functions and decorators(wrappers)

Thanks for reading my question. As I'm still new to Python, I would like to ask about the () in Python.
def addOne(myFunc):
def addOneInside():
return myFunc() + 1
return addOneInside # <-----here is the question
#addOne
def oldFunc():
return 3
print oldFunc()
Please note that on line four, although the programme returns a function, it does not need parentheses(). Why does it NOT turn out with an error for syntax error? Thank you very much for your answers in advance!
The parentheses are used to run a function, but without them the name still refers to the function just like a variable.
return myFunc() + 1
This will evaluate the myFunc function, add 1 to its value and then return that value. The brackets are needed in order to get the function to run and return a numeric value.
return addOneInside
This is not actually running addOneInside, it is merely returning the function as a variable. You could assign this to another name and store it for later use. You could theoretically do this:
plusOne = addOneInside
plusOne()
And it will actually call the addOneInside function.
The particular instance in your initial question is known as a Decorator, and it's a way for you to perform code on the parameters being passed to your function. Your example is not very practical, but I can modify it to show a simple use case.
Let's say that you want to only have positive numbers passed to your function. If myFunc is passed a negative number, you want it to be changed to 0. You can manage this with a decorator like this.
def addOne(myFunc):
def addOneInside(num):
if num < 0:
num = 0
return myFunc(num)
return addOneInside # <-----here is the question
#addOne
def oldFunc(number):
return number
To explain, the #addOne is the decorator syntax, and it's attaching the addOneInside function to be called on the argument/s of oldFunc whenever you call it. So now here's some sample output:
oldFunc(-12)
>>> 0
oldFunc(12)
>>> 12
So now you could add logic to oldFunc that operates independently of the parameter parsing logic. You could also relatively easily change what parameters are permitted. Maybe there's also a maximum cap to hit, or you want it to log or note that the value shouldn't be negative. You can also apply this decorator to multiple functions and it will perform the same on all of them.
This blogpost explained a lot for me, so if this information is too brief to be clear, try reading the long detailed explanation there.
Your indentation in function addOne() was incorrect (I have fixed it), but I don't think that this was your problem.
If you are using Python3, then print is a function and must be called like this:
print(oldFunc())

Calling a function from a set variable? [duplicate]

This question already has answers here:
Calling a function from string inside the same module in Python?
(2 answers)
Python function pointer
(8 answers)
Closed 9 years ago.
Im writing a python script and what I would like to do is capture the input into a variable and then use that to call a function with that name. Here is an example:
def test():
print "You want to do a test!"
option = raw_input("What do you want to do? ") #User types in test
option()
Now this isnt working since python is not seeing option as a variable but rather is trying to call the function "option". What is the bast way to go about doing this?
eval() will work, but as #MattDMo said it can be dangerous.
A much safer way to do this, if your functions are module globals:
globals()[option]()
globals() is a dictionary mapping strings to the module global objects those strings are bound to. So globals()[option] looks up the string bound to option in that dict, and returns the object; e.g., globals["test"] returns the function object for test(). Then adding () at the end calls that function object. Bingo - you're done.
You want to be very careful about running arbitrary code, but if you absolutely need to, you can use the eval() function.
What might be a better way is to give your user a menu of options, then do testing on the contents of option to see which one they picked, then run that function.
You can use python eval.
From the help page, eval evaluates the source in the context of globals and locals. The source may be a string representing a Python expression or a code object as returned by compile().
For example:
def a():
print "Hello"
inp = raw_input()
eval(inp + "()")
On entering a at the stdin, the function a will be executed. Note that this could be dangerous without any safety checks.
This is, I suppose, an actual use for bare input:
option = input("What do you want to do? ") #User types in test
option()
This is semantically equivalent to eval(raw_input()). Note that in python 3, raw_input becomes input so you will explicitly have to eval it.
The usual caveats of this type of operation being incredibly unsafe apply. But I think that's obvious from your requirement of giving the user access to run arbitrary code, so...
I like using a dict in situations like this. You can even specify a default option if the user provides an answer that isn't expected.
def buy_it():
print "use it"
def break_it():
print "fix it"
def default():
print "technologic " * 4
menu = {"buy it": buy_it, "break it": break_it}
option = raw_input("What do you want to do? ")
menu.get(option, default)()

Categories