In a Python program (with more than one user defined functions), I want to specify which function to use through command line arguments. For e.g., I have the following functions, func1(), func2(), func3() in my Python program, and I am using the following technique presently:
python prog.py -func func2"
My program is something like this:
from __future__ import division
import numpy as np
import argparse
parser = argparse.ArgumentParser(description='')
parser.add_argument('-func', help='')
args = parser.parse_args()
func_type = globals()[args.func]()
def func1():
print "something1"
def func2():
print "something2"
def func3():
print "something3"
func_type()
I get the following error:
KeyError: 'func2'
I will really appreciate if someone can tell me how I can implement the desired functionality.
Two simple mistakes related to func_type = globals()[args.func]()
The functions you are looking for have not been defined yet. Move the function definitions above this line.
You are calling the function instead of saving a reference to it in variable func_type.
Related
Using the very interesting answer provided here, I would like to be able to use argparse and execute multiple functions without having to define the arguments to each function. Otherwise the code is very overloaded or one has to multiply files to run different functions, which is not very practical either.
In the following example, the functions function1 and function2 have different arguments such as: function1(arg1: int, arg2: bool) and function2(arg3: float, arg4: str)
# file test.py
import argparse
from file1 import function1
from file2 import function2
FUNCTION_MAP = {'function1' : function1, 'function2': function2}
parser = argparse.ArgumentParser()
parser.add_argument('command', choices=FUNCTION_MAP.keys())
# no specific argument to add here.
args = parser.parse_args()
func = FUNCTION_MAP[args.command]
func(**vars(args))
The following commands with -- arguments do not work.
python test.py "function1" --arg1=10 --arg2=True
python test.py "function2" --arg3=2.4 --arg4="a_file.csv"
command as python test.py "function1" works but asks me the arguments of the function1.
Thanks for your help.
If functions will be shuttling around/sharing lots of the same data, sounds like you want a class/object?
myobj.fn1() and myobj.fn2() will both have implicit access to the myobj object's data.
Use argparse input to define the initial instance via your class' __init__(self, x, y ...) method.
I have 2 python files. One file has all of the functions, the other file has a function which calls functions from the first file. Here is a simplified version of what I have.
file1.py
def one():
print("Hello World")
def two():
print("Salutations Earth")
def three():
print("Greetings World")
file2.py
import file1
function_id = input("Which function would you like? Please enter(one, two or three): ")
file1.function_id()
Clearly, this is not going to work because there is no function named 'function_id' in file1. However, I am not sure how to call the functions from file1 dynamically. I looked on youtube and one of the videos suggested to use eval() but it did not work for me. Thank You for your time!
In file1.py, add a function dictionary like this:
function_dict = {'one':one, 'two':two, 'three':three}
Then in file2.py, replace file1.function_id() with this:
file1.function_dict[function_id]()
Use getattr() on the module file1
import file1
function_name = input("Which function would you like? Please enter(one, two or three): ")
function = getattr(file1, function_name, None)
if function:
function()
else:
print(f"No such function: {function}")
Note: executing arbitrary user input is not secure.
I have a module, called T, has a couple of functions and the main part, where calls these functions. From another module, I want to use this module. The main scheme is like:
"""Module T"""
def parse_args():
parser = argparse.ArgumentParser(description='Desc')
parser.add_argument('something')
def foo():
pass
if __name__ == "__main__":
args = parse_args()
foo()
And the other module I want to use:
"""Module M"""
def foo():
pass
def do_something():
"""Where I want to use module T's main"""
I have used module T from terminal with arguments and worked fine. The question may be easy but, how can I use it's main with parameters?
Add a run function (or main or whatever you like) to your module that accepts your command line, and make sure that parse_args optionally accepts an arbitrary list as well:
def parse_args(args=None):
parser = argparse.ArgumentParser(description='Desc')
parser.add_argument('something')
return parser.parse_args(args)
def foo():
pass
def run(args=None):
args = parse_args(args)
foo()
if __name__ == "__main__":
run()
Basically, instead of trying to simulate the import operation and injecting sys.argv (which might actually be possible), you can just factor out the part that the import runs that's of interest to you, and provide access to it:
import T
T.run() # Uses sys.argv
T.run(['my', 'list', '--of', 'args'])
While totally untested, you can possibly also do something like the following (please don't though, this is just for fun):
import sys
from importlib import reload
sys.argv[1:] = my_args
if 'T' in sys.modules:
reload(sys.modules['T'])
else:
import T
But then you'd need to remove the import guard in T.py. Unless you wanted to implement your own module loading sequence, which would let you inject T.__name__, rather than having to modify the import guard: Injecting variables into an import namespace
The if __name__ ... pattern is executed if the script is called directly, so the real solution is to call foo in your entrypoint. The if __name__ ... patter basically protects lines of code from being executed on import. For example, this is a very convenient pattern for testing - just put your tests in the protected block. The straightforward way to do what you're asking:
"""Module M"""
def bar():
pass
def do_something(args):
args = parse_args()
module_t.foo()
If you want module M to be completely "fire and forget" then Mad Physicist's answer is for you.
I'm doing genetic programming framework and I need to be able to execute some string representing complete python programs. I'm using Python 2.7. I have a config class in which the primitive sets are defined. Lets say
class Foo():
def a(self,x):
return x
def b(self,y):
return y
I'm extracting the functions with the python inspect module and I want to create some executable source code with imports and everything. I end up with a string that looks like this
import sys
def a(x,y):
return x
def b(y):
return y
def main(x,y)
lambda x,y: a(b(y),a(x,y))
main(*sys.argv)
My problem is that I don't know how to pass command line arguments to the string I'm running with eval(). How can I pass command line arguments to a source file I want to run with eval()?
Edit: There are millions of individuals so writing to a file is not a great option.
Edit: I made a mistake. The eval() method is used only for expressions and not statements so using exec() is the correct approach
eval("function_name")(arg1, arg2)
or if you have a list of arguments:
arguments= [arg1,arg2,arg3,something]
eval("function_name")(*arguments)
You have three options, roughly speaking. You can keep going with eval(),you could actually write the string as a file and execute it with subprocess.Popen(), or you could call the function something besides main() and call it after defining it with eval().
exec() way:
In the string you want to exec
main(#REPLACE_THIS#)
Function to evaluate
import string
def exec_with_args(exec_string,args):
arg_string=reduce(lambda x,y:x+','+y,args)
exec_string.replace("#REPLACE_THIS#", arg_string)
Subprocess way:
import subprocess
#Write string to a file
exec_file=open("file_to_execute","w")
exec_file.write(string_to_execute)
#Run the python file as a separate process
output=subprocess.Popen(["python","file_to_execute"].extend(argument_list),
stdout=subprocess.PIPE)
Function Definition Way
In the string you want to exec
def function_name(*args):
import sys
def a(x,y):
return x
def b(y):
return y
def inner_main(x,y):
lambda x,y: a(b(y),a(x,y))
inner_main(*args)
Outer code
exec(program_string)
function_name(*args)
I have a file that contains several python functions, each with some statements.
def func1():
codeX...
def func2():
codeY...
codeX and codeY can be multiple statements. I want to be able to parse the file, find a function by name, then evaluate the code in that function.
With the ast module, I can parse the file, find the FunctionDef objects, and get the list of Stmt objects, but how do I turn this into bytecode that I can pass to eval? Should I use the compile module, or the parser module instead?
Basically, the function defs are just used to create separate blocks of code. I want to be able to grab any block of code given the name and then execute that code in eval (providing my own local/global scope objects). If there is a better way to do this than what I described that would be helpful too.
Thanks
I want to be able to grab any block of code given the name and then execute that code ... (providing my own local/global scope objects).
A naive solution looks like this. This is based on the assumption that the functions don't all depend on global variables.
from file_that_contains_several_python_functions import *
Direction = some_value
func1()
func2()
func3()
That should do exactly what you want.
However, if all of your functions rely on global variables -- a design that calls to mind 1970's-era FORTRAN -- then you have to do something slightly more complex.
from file_that_contains_several_python_functions import *
Direction = some_value
func1( globals() )
func2( globals() )
func3( globals() )
And you have to rewrite all of your global-using functions like this.
def func1( context )
globals().update( context )
# Now you have access to all kinds of global variables
This seems ugly because it is. Functions which rely entirely on global variables are not really the best idea.
Using Python 2.6.4:
text = """
def fun1():
print 'fun1'
def fun2():
print 'fun2'
"""
import ast
tree = ast.parse(text)
# tree.body[0] contains FunctionDef for fun1, tree.body[1] for fun2
wrapped = ast.Interactive(body=[a.body[1]])
code = compile(wrapped, 'yourfile', 'single')
eval(code)
fun2() # prints 'fun2'
Take a look at grammar in ast doc: http://docs.python.org/library/ast.html#abstract-grammar. Top-level statement must be either Module, Interactive or Expression, so you need to wrap function def in one of those.
If you're using Python 2.6 or later, then the compile() function accepts AST objects in addition to source code.
>>> import ast
>>> a = ast.parse("print('hello world')")
>>> x = compile(a, "(none)", "exec")
>>> eval(x)
hello world
These modules have all been rearranged for Python 3.