Related
I'm simply writing a Python program that takes in 2 integers and returns the sum. The problem I encounter is that the terminal never displays the returned value, so I have to resort to making a print statement. Is there any way to have the terminal display the returned value of the program?
The code is as follows:
import argparse
def simple_addition():
parser = argparse.ArgumentParser(description = "Simple Addition Program to Test CLI")
# each line add AN argument to our terminal inout
parser.add_argument("first_number", type = int, help = "enter the first integer")
parser.add_argument("second_number", type = int, help = "enter the second integer")
args = parser.parse_args()
# storing the entered argument internally within our code for ease of access
first = args.first_number
second = args.second_number
# calculate and return the sum
sum = first + second
print("A PRINT CALL (not return): ", sum)
return sum
simple_addition()
Following is a screenshot of the terminal when I run this program.
#! /usr/bin/env python3
import argparse
def simple_addition():
parser = argparse.ArgumentParser(description = "Simple Addition Program to Test CLI")
# each line add AN argument to our terminal inout
parser.add_argument("first_number", type = int, help = "enter the first integer")
parser.add_argument("second_number", type = int, help = "enter the second integer")
args = parser.parse_args()
# storing the entered argument internally within our code for ease of access
first = args.first_number
second = args.second_number
# calculate and return the sum
sum = first + second
#print("A PRINT CALL (not return): ", sum)
return sum
if __name__ == '__main__':
print(simple_addition())
add shebang on first line and chmod +x
do not print inside the function
do it only if it's main (so you can import the module if needed)
then you can invoke it directly
./"CLI Testing.py" 35 45
Is there any way to have the terminal display the returned value of the program?
Yes, by using print. That's what it's for.
so I have to resort to making a print statement
You do not "resort" to it in the same way as you do not "resort" to the + operator in order to add two numbers. It's just what it's there for.
It's true, however, that printing and returning the result from a function is not good design (for example, it prevents you from reusing the function in cases where you don't want to print the result).
Instead of printing the result from inside the function it would be better to print the returned value in the calling code:
print(simple_addition())
or
result = simple_addition()
print(result)
I am trying to create a function in which I will store formulas for my converter. When X formula will be needed, it will be called from it. When trying it with simple 0:a+b it works when returning, but when trying to store it as string meters_to_foots, it doesn't work. I need to have that formula stored as something since I need to output it later.Here is a part of the code which I have problems with. NameError: name 'meters_input' is not defined
def my_formulas(i):
switcher={
0:(meters_input/0.3048)
}
return switcher.get(i,"Invalid formula")
distance_pick=input("Please pick one of the current convertions : \n \n1.Meters to X \n2.Inches to X \n3.Feets to X ")
if(distance_pick=="1"):
cls()
distance_choice = input ("Please select which converter would you like to use ! : \n \n1.Meter to Foot \n2.Meter to Yard \n3.Meters to Inches ")
if(distance_choice=="1"):
meters_input=float(input("Make sure to enter distance in Meters ! : "))
my_formulas(0)
print ("\nYou entered", meters_input , "meters, which is equal to",my_formulas(0),"foots.")
time.sleep (3)
cls ()
read_carefully_message()
To create a function in Python use either lambda functions or the regular function definition. Examples are respectively:
def divide(meters_input):
return meters_input / 0.3048
or
divide = lambda meters_input: meters_input / 0.3048
Generally the regular function definition is preferred since it improves readability. You can define your function mapping as follows:
def my_formulas(i):
switcher={
0:divide # do not write divide()
}
If these will always be simple functions you can use a lambda expression for this:
def my_formulas(i):
switcher= {
0:lambda meters_input: meters_input/0.3048
}
return switcher.get(i,"Invalid formula")
my_formulas(0)(27) #88.58267716535433
If your function lookup will always be a number starting with zero you might be better off storing the functions as an array. You could do something like this as well:
def my_formulas(index):
def meters2Feet(meters):
return meters/0.3048
def hours2Minutes(hours):
return hours * 60
def invalid(*args):
return "Invalid formula"
lookup = [
meters2Feet,
meters2Feet
]
if index >= len(lookup):
return invalid
return lookup[index]
my_formulas(0)(27) # 88.58267716535433
It's a little more complicated, but probably easier to read and understand.
Try changing your function to this:
def my_formulas(i):
switcher = (i/0.3048)
return switcher
The "i" in the function is a local variable for the function. In your code you are passing 0 into the my_formulas() function. i then becomes 0, but meters_input is out of scope for the function.
I want to call a python script through the command line with this kind of parameter (list could be any size, eg with 3):
python test.py --option1 ["o11", "o12", "o13"] --option2 ["o21", "o22", "o23"]
using click. From the docs, it is not stated anywhere that we can use a list as parameter to #click.option
And when I try to do this:
#!/usr/bin/env python
import click
#click.command(context_settings=dict(help_option_names=['-h', '--help']))
#click.option('--option', default=[])
def do_stuff(option):
return
# do stuff
if __name__ == '__main__':
do_stuff()
in my test.py, by calling it from the command line:
python test.py --option ["some option", "some option 2"]
I get an error:
Error: Got unexpected extra argument (some option 2])
I can't really use variadic arguments as only 1 variadic arguments per command is allowed (http://click.pocoo.org/5/arguments/#variadic-arguments)
So if anyone can point me to the right direction (using click preferably) it would be very much appreciated.
If you don't insist on passing something that looks like a list, but simply want to pass multiple variadic arguments, you can use the multiple option.
From the click documentation
#click.command()
#click.option('--message', '-m', multiple=True)
def commit(message):
click.echo('\n'.join(message))
$ commit -m foo -m bar
foo
bar
You can coerce click into taking multiple list arguments, if the lists are formatted as a string literals of python lists by using a custom option class like:
Custom Class:
import click
import ast
class PythonLiteralOption(click.Option):
def type_cast_value(self, ctx, value):
try:
return ast.literal_eval(value)
except:
raise click.BadParameter(value)
This class will use Python's Abstract Syntax Tree module to parse the parameter as a python literal.
Custom Class Usage:
To use the custom class, pass the cls parameter to #click.option() decorator like:
#click.option('--option1', cls=PythonLiteralOption, default=[])
How does this work?
This works because click is a well designed OO framework. The #click.option() decorator usually instantiates a click.Option object but allows this behavior to be over ridden with the cls parameter. So it is a relatively easy matter to inherit from click.Option in our own class and over ride the desired methods.
In this case we over ride click.Option.type_cast_value() and then call ast.literal_eval() to parse the list.
Test Code:
#click.command(context_settings=dict(help_option_names=['-h', '--help']))
#click.option('--option1', cls=PythonLiteralOption, default=[])
#click.option('--option2', cls=PythonLiteralOption, default=[])
def cli(option1, option2):
click.echo("Option 1, type: {} value: {}".format(
type(option1), option1))
click.echo("Option 2, type: {} value: {}".format(
type(option2), option2))
# do stuff
if __name__ == '__main__':
import shlex
cli(shlex.split(
'''--option1 '["o11", "o12", "o13"]'
--option2 '["o21", "o22", "o23"]' '''))
Test Results:
Option 1, type: <type 'list'> value: ['o11', 'o12', 'o13']
Option 2, type: <type 'list'> value: ['o21', 'o22', 'o23']
The following can be an easier hack fix:
#!/usr/bin/env python
import click
import json
#click.command(context_settings=dict(help_option_names=['-h', '--help']))
#click.option('--option', help='Whatever')
def do_stuff(option):
try:
option = json.loads(option)
except ValueError:
pass
# do stuff
if __name__ == '__main__':
do_stuff()
This can help you to use 'option' as a list or a str.
#Murphy's "easy hack" almost worked for me, but the thing is that option will be a string unless you single quote the options, so I had to do this in order to recompose the list:
#!/usr/bin/env python
import click
import json
#click.command(context_settings=dict(help_option_names=['-h', '--help']))
#click.option('--option', help='Whatever')
def do_stuff(option):
try:
option = json.loads(option)
# option = str(option) # this also works
except ValueError:
pass
option = option[1:-1] # trim '[' and ']'
options = option.split(',')
for i, value in enumerate(options):
# catch integers
try:
int(value)
except ValueError:
options[i] = value
else:
options[i] = int(value)
# Here use options as you need
# do stuff
if __name__ == '__main__':
do_stuff()
You could catch some other types
To use it, enclose the list into quotes:
python test.py --option "[o11, o12, o13]"
Or you can avoid quotes by not leaving spaces:
python test.py --option [o11,o12,o13]
The answer of Stephen Rauch gave me some issues when working with Kubernetes arguments. This because the string formatting becomes a hassle and often new lines, single quotation marks or spaces were added before and after the array. Hence I made my own parser to improve this behaviour.
This code should be self explanatory.
Note that this code does not support single or double quotation marks ' or " in the variables itself.
Custom class:
class ConvertStrToList(click.Option):
def type_cast_value(self, ctx, value) -> List:
try:
value = str(value)
assert value.count('[') == 1 and value.count(']') == 1
list_as_str = value.replace('"', "'").split('[')[1].split(']')[0]
list_of_items = [item.strip().strip("'") for item in list_as_str.split(',')]
return list_of_items
except Exception:
raise click.BadParameter(value)
Custom class usage:
#click.option('--option1', cls=ConvertStrToList, default=[])
Click supports an option taking multiple arguments, as long as the number of arguments is predetermined. The arguments are separated by whitespace with no list-like syntax: one would write --my-2-arg-option arg1 arg2 rather than --my-2-arg-option ["arg1", "arg2"].
This response does answer your question about "how to pass several lists of arguments to #click.option," just that the lists need to be given without brackets or commas on the command line. A Python list could be formatted this way as follows, using shlex.join to add quotation marks when necessary:
>>> import shlex
>>> args = ["o11", "o12", "o13"]
>>> shlex.join(args)
'o11 o12 o13'
>>> args_needing_quotes = ["I have whitespace",
"$I_LOOK_LIKE_A_VARIABLE",
"$(i_have_special_characters)#!\n > *"]
>>> shlex.join(args_needing_quotes)
"'I have whitespace' '$I_LOOK_LIKE_A_VARIABLE' '$(i_have_special_characters)#!\n > *'"
Option that takes multiple arguments, all of the same type
This kind of option seems to be what you are looking for, and can be implemented with the following code (call it script1.py):
import click
#click.command()
#click.option("--option1", nargs=3)
def do_stuff(option1):
print("Option 1 is", option1)
do_stuff()
The parameter nargs tells Click how many arguments the option must accept; by default, nargs is 1.
Running this code prints the following output:
$ python script1.py --option1 four 4 IV
Option 1 is ('four', '4', 'IV')
We can see that the variable option1 is a tuple of three str values.
If fewer or more than 3 arguments are given for option1, then the script exits immediately:
$ python script1.py --option1 four 4
Error: Option '--option1' requires 3 arguments.
If option1 is omitted, then it defaults to None:
$ python script1.py
Option 1 is None
Default values of multi-argument options
A default value can be specified when the option is created. Note that the default value should also be a tuple of three str values to avoid any unexpected behavior. Particularly, it should not be a list (or any other mutable type), as mutable default arguments can cause unexpected behavior. Call the code with this change script2.py:
#click.option("--option1", nargs=3, default=('', '', ''))
Now the script prints the default when run with no arguments:
$ python script2.py
Option 1 is ('', '', '')
Types other than strings
Click will also automatically cast values to a different data type if given. Let script3.py be
import click
#click.command()
#click.option("--option1", nargs=3, type=float)
def do_stuff(option1):
print("Option 1 is", option1)
do_stuff()
Now option1 is a tuple of three float values:
$ python script3.py --option1 1 2.718 3.142
Option 1 is (1.0, 2.718, 3.142)
Option that takes multiple arguments of different data types
The previous examples showed how to create an option that takes multiple values of the same data type. What about an option that takes arguments of multiple data types?
Click provides a way to do this as well. Instead of setting nargs, set type to be a tuple of the desired data types. For example, let script4.py be
import click
#click.command()
#click.option("--comp", type=(float, str, float))
def calculate(comp):
num1, op, num2 = comp
if op == "+":
result = num1 + num2
elif op == "-":
result = num1 - num2
else:
raise ValueError(f"Unsupported operation: {op}")
print(f"{num1} {op} {num2} = {result}")
calculate()
Then we can use our rudimentary calculator:
$ python script4.py --comp 3 + 6
3.0 + 6.0 = 9.0
$ python script4.py --comp -1.2 - 3.7
-1.2 - 3.7 = -4.9
If any of the values are invalid, then click will raise an error automatically:
$ python script4.py --comp 1 + two
Usage: script4.py [OPTIONS]
Try 'script4.py --help' for help.
Error: Invalid value for '--comp': 'two' is not a valid float.
Option that can be given multiple times and takes multiple values
Click can also create options that can be given multiple times using the multiple keyword (script5.py):
import click
#click.command()
#click.option("--option1", nargs=2, multiple=True)
def do_stuff(option1):
print(option1)
do_stuff()
Now we see that option1 becomes a tuple of tuples of two strs each:
$ python script5.py --option1 3 a --option1 b 7
(('3', 'a'), ('b', '7'))
We can also mix multiple=True with the type keyword in script6.py:
import click
#click.command()
#click.option("--comps", type=(float, str, float), multiple=True)
def calculate(comps):
for comp in comps:
num1, op, num2 = comp
if op == "+":
result = num1 + num2
elif op == "-":
result = num1 - num2
else:
raise ValueError(f"Unsupported operation: {op}")
print(f"{num1} {op} {num2} = {result}")
calculate()
This functionality can allow us to, for example, code a simple calculator that performs multiple operations in one call to script6.py:
python script6.py --comps 4 - -7 --comps -8 + 4.2 --comps 16 - 34.1
4.0 - -7.0 = 11.0
-8.0 + 4.2 = -3.8
16.0 - 34.1 = -18.1
The full documentation for multi-value options in Click can be found here.
Note: I ran all code examples in Python 3.11.0 with Click 8.1.3
I'm having a hard time to understand how to work with functions - I can make then but after that I don't know how to use them. My question is how can I print this code with a function?
string = "Hello"
reverse = string[::-1]
print(reverse)
I tried putting it in a function but I cannot make it print Hello.
def reverse_a_string(string):
string = "Hello"
reverse = string[::-1]
print(reverse)
also tried this
def reverse_a_string(string):
string = "Hello"
reverse = string[::-1]
print(reverse)
Nothing seems to work. I'm having same problem with this as well.
total = 0
def length(words):
for i in words:
total += 1
return total
Functions without a return value
Functions that just take action or do something without returning a value (for example, print).
Functions that don't return a value can be defined like that:
def sayHello():
print "Hello!"
And can be used (called) like that:
sayHello()
And the output will be:
Hello!
Function parameters
A function can also receive parameters (type of variables) from the caller. It's better to demonstrate it with an example.
A function that receives a name and greets this name:
def sayHelloTo(name):
print "Hello", name
It can be called like that:
sayHelloTo("Yotam")
And the output will be:
Hello Yotam
The parameters are the function's input.
Functions with a return value
Other functions, unlike sayHello() or sayHelloTo(name) (that just do something) can return a value. For example, let's make a function that rolls a dice (returns a random number between 1 and 6).
from random import randint
def rollDice():
result = randint(1, 6)
return result
The return keyword just sets the output value of the function and exits the function. An example use of the rollDice function will be:
dice = rollDice()
print "The dice says", dice
When the function hits a return keyword, it finishes and the return value (in our case, the variable result) will be placed instead of the function call. Let's assume randint(1, 6) has produced the number 3.
Result becomes 3.
Result is returned.
Now, instead of the line:
dice = rollDice()
We can treat the line as:
dice = 3
(rollDice() was replaced with 3)
Functions with parameters and a return value
Some functions (for example, math functions) can take inputs AND produce outputs. For example, let's make a function that receives 2 numbers and outputs the greater one.
def max(a,b):
if a > b:
return a
else:
return b
What it does is pretty clear, isn't it? If a is greater, it returns the value of it. Otherwise, returns the value of b.
It can be used like that:
print max(4, 6)
And the output will be:
6
Now, your case
What you want to do is a function that reverses a string. It should take 1 parameter (input) - the string you want to reverse, and output 1 value - the reversed string. This can be accomplished like that:
def reverse_a_string(my_text):
return my_text[::-1]
now you can do something like that:
s = raw_input("Please enter a string to be reversed\n") #input in Python3
r = reverse_a_string(s)
print r
r will contain the reversed value of s, and will be printed.
About your second function - well, I assume that based on this answer you can make it yourself, but comment me if you need assistance with the second one.
Local variables
About your 3rd example:
def reverse_a_string(string):
string = "Hello"
reverse = string[::-1]
print(reverse)
This is something that is really worth delaying and understanding.
the variable reverse is first used inside the function. This makes it a local variable.
This means that the variable is stored in the memory when the function is called, and when it finishes, it is removed. You can say it's lifetime is from when the function is called to when the function is done.
This means that even if you called reverse_a_string(string), you wouln't be able to use the reverse variable outside of the function, because it would be local.
If you do want to pass a value like that, you have to "declare" your variable outside of the function and to use the global keyword, like that:
reverse = "" #This makes reverse a global variable
def reverse_a_string(string):
global reverse #Stating that we are going to use the global variable reverse
reverse = string[::-1]
# Then you can call it like that:
reverse_a_string("Hello")
print reverse
The output will be
olleH
Although it's strongly not recommended to do it in Python, or in any other language.
Once you create a function you must call it. You have created the function reverse_a_string but then you never actually call it. Think about a function as a button that does something everytime it is pushed (or in our case called). If you never push the button then although it has the potential to do something, it never will. In order for the set of instructions to happen we need to push the button (or in our case call the function). So in order for your code to work you first need to define the function then actually call it:
def reverse_a_string():
string="Hello"
reverse = string[::-1]
print reverse
reverse_a_string()
Result: 'olleH'
If you want to pass your own string in to the function so it doesn't just return 'olleH' all the time your code needs to look like such:
def reverse_a_string(stringThatWillBeReversed):
reverse = stringThatWillBeReversed[::-1]
print reverse
reverse_a_string('whateverStringYouWant')
Result: The reverse of the string you entered.
Hope that helps!
I don't know whether you are asking how to define functions in python or something else
If you want to learn python functions, go to http://www.tutorialspoint.com/python/python_functions.htm or just write python tutorial in google, you will get billions of good sites
def reverse_a_string(string):
#function definition
reverse = string[::-1]
print(reverse)
#function call
reverse_a_string("your string")
But you to define function for this, you could simply do
print( string[::-1] )
# defines the 'Reverse a String' function and its arguments
def reverse_a_string():
print(string)
reverse = string[::-1]
print(reverse)
print("Type a string") # asks the user for a string input
string = input() # assigns whatever the user input to the string variable
reverse_a_string() # simply calls the function
for functions, you have to define the function, then simply call it with the function name i.e. funtion()
In my example, I ask for a string, assign that to the variable, and use it within the function. If you just want to print hello (I'm a little unclear from your question) then simply including the print("hello") or w/ variable print(string) will work inside the function as well.
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 an input to direct to that function like
w=raw_input('Please input the function you want to use')
or
w='add'
Is there any way to use w to refer to the function add?
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.
One safe way is to map from names to functions. It's safer than using eval.
function_mappings = {
'add': add,
}
def select_function():
while True:
try:
return function_mappings[raw_input('Please input the function you want to use')]
except KeyError:
print 'Invalid function, try again.'
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.
unutbu's solution is what I would normally use, but for completeness sake:
If you are specifying the exact name of the function, you can use eval, although it is highly discouraged because people can do malicious things:
eval("add")(x,y)
Just use function reference:
def pwr(x, y):
return x ** y
def add(x, y):
return x + y
dispatcher = { 'pwr' : pwr, 'add' : add}
def call_func(x, y, func):
try:
return dispatcher[func](x, y)
except:
return "Invalid function"
call_func(2, 3, 'add')
Simple and secure.
If you are implementing a shell-like application where the user enter some command (such as add), and the application responses (return the sum), you can use the cmd module, which handles all the command interactions and dispatching for you. Here is an example:
#!/usr/bin/env python
import cmd
import shlex
import sys
class MyCmd(cmd.Cmd):
def do_add(self, arguments):
'''add - Adds two numbers the print the sum'''
x, y = shlex.split(arguments)
x, y = int(x), int(y)
print x + y
def do_quit(self, s):
'''quit - quit the program'''
sys.exit(0)
if __name__ == '__main__':
cmd = MyCmd()
cmd.cmdloop('type help for a list of valid commands')
Here is a sample running session:
$ python cmd_tryout.py
type help for a list of valid commands
(Cmd) help add
add - Adds two numbers the print the sum
(Cmd) add 5 3
8
(Cmd) quit
At the prompt (Cmd), you can issue the help command which you get for free. Other commands are add and quit which correspond to the do_add() and do_quit() functions.
Note that help command displays the docstring for your function. The docstring is a string immediately follows the function declararation (see do_add() for example).
The cmd module does not do any argument spliting, parsing, so you have to do it yourself. The do_add() function illustrates this.
This sample program should be enough to get you started. For more information look up the cmd help page. It is trivia to customize the prompt and other aspect of your program.
I had the same problem.
The way I recommend you to handle it is to create a temporary Python file to store the function the user input. Here's an example I used in a program I wrote to draw representations of mathematical functions:
with open("function.py",'w') as file:
f=input('enter the function you want to draw example: 2*x+1 or e**x :\n')
file.write("from math import *\ndef f(x):\n\treturn "+f)
This will create a file containing the function I want to call.
Next, you must call the function you wrote in the file to your program:
from function import f
Now you can use your function as normal python function.
If you want, you can also delete the file where you stored your function using os.remove:
import os
os.remove("function.py")
To help you understand, here is my program to draw mathematical functions:
import numpy
import cv2
import os
from math import *
def generate(f,a,b,min,max,functionname='noname'):
ph=(b-a)/1920
pv=(max-min)/1080
picture=numpy.zeros((1080,1920))
for i in range(0,1920):
picture[1079-(int((f(a+(i+1)*ph)*1080/max))),i]=255
for i in range(1920):
picture[1079-(int((f(a+(i+1)*ph)*1080/max)))+1,i]=255
cv2.imwrite(functionname+'.png',picture)
with open("function.py",'w') as file:
f=input('enter the function you want to draw example: or e**x :\n')
file.write("from math import *\ndef f(x):\n\treturn "+f)
from function import f
os.remove("function.py")
d=input('enter the interval ,min ,max and the image file name. Separate characters with spacebar. Example: 0 1 0 14 exponontielle :\n').split(" ")
generate(f,int(d[0]),int(d[1]),int(d[2]),int(d[3]),d[4])
def add(x,y):
print(x+y)
def subtract(x,y):
print(x-y)
function_list = {'add', 'subtract'}
def caller(func, x, y):
eval(func)(x,y) # more security exploits
if func in function_list:
eval(func)(x,y) # less security exploits
caller("add", 1, 2)
I've had many situation where I've needed to compare a string to an int and vice versa within a Django template.
I created a filter that allowed me to pass in the function name and using eval() convert it.
Example:
Template:
{% ifequal string int|convert:'str' %} do something {% endifequal %}
Template Filter (where i use a string to call the function name):
#register.filter
def convert(value, funcname):
try:
converted = eval(funcname)(value)
return converted
except:
return value
With reference to John Curry's question above ... if you want a version of Jefferson Felix's code that handles multiple arguments, then the simplest solution is to provide the arguments in a list, and arrange for each of the dispatched functions to check the argument count before proceeding.
A simple version that I've just tested in Visual Studio code is as follows:
import math
def sin(args):
argc = len(args)
if (argc == 1):
result = math.sin(args[0])
else:
result = None
return(result)
def sum(args):
argc = len(args)
if (argc == 2):
result = args[0] + args[1]
else:
result = None
return(result)
def dot_product(args):
argc = len(args)
if (argc == 2):
vector1 = args[0]
vector2 = args[1]
if (len(vector1) == 3 and len(vector2) == 3):
result = (vector1[0] * vector2[0]) + (vector1[1] * vector2[1]) + (vector1[2] * vector2[2])
else:
result = None
else:
result = None
return(result)
dispatcher = {"sin" : sin, "sum" : sum, "dot_product" : dot_product}
def call_func(dispatcher, func_name, args):
func_list = list(dispatcher.keys())
if (func_list.count(func_name) == 0):
return(None)
else:
return(dispatcher[func_name](args))
val = call_func(dispatcher, "sin", [0.6])
print(f"Sine is : {val}")
val = call_func(dispatcher, "sum", [4, 6])
print(f"sum is : {val}")
val = call_func(dispatcher, "dot_product", [[3, 7, 2], [5, 9, 4]])
print(f"dot product is : {val}")
The output looks as follows:
Sine is : 0.5646424733950354
sum is : 10
dot product is : 86
Of course, a more sophisticated version would include better error trapping that simply returning "None" if an error is found, but the above can be used as a template to build upon. Likewise, the dot_product function could be improved to handle vectors of any dimension, but I leave that as an exercise for the reader ...
[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()
This question belongs to an arcane Python era obviously, but I thought this might be useful for people getting here from search engines..
Nowadays, you can do something like this (no manual mappings required):
func = locals()[ name ]
print( f'Found local function {func}' )
func()
Of course, for any real use case you should check that you actually found anything before executing it!