I am writing a python program where in I have included another python file.
The python file included has a method which I want to invoke from the calling script.
Like:
#!/usr/bin/python
include script1
method = sys.argv[1] # values may be - create or destroy
if method == "create":
script1.create()
elif method == "destroy":
script1.destroy()
Now, what I want is,
#!/usr/bin/python
include script1
method = sys.argv[1] # values may be - create or destroy
script1.method()
and, it should use the value inside the variable method instead of trying to call the module called method.
You can use getattr.
method= sys.argv[1]
getattr(script1, method)()
To call functions from script1, you could turn it into a module.
script1.py:
def create():
pass
def destroy():
pass
script2.py:
import script1
script1.create()
script1.destroy()
Related
I am trying to find a way to share a variable between multiple python scripts. I have the following code:
b.py
my_variable = []
a.py
from b import my_variable # import the value
def run():
global x
x = my_variable.append("and another string")
print(my_variable)
if __name__ == '__main__':
run()
c.py
import a
print(a.x)
a.py runs just fine without giving any error. However, when I run the c.py file, it gives off the following error:
Traceback (most recent call last):
File "E:/MOmarFarooq/Programming/Projects/Python Projects/Variables across files/c.py", line 2, in
<module>
print(a.x)
AttributeError: module 'a' has no attribute 'x'
What I want the code to do is, print the new value of my_variable after it has been changed in a.py . Is there any way I can do that?
the error occurred because you never called the run function from a.py. The if __name__=='__main__': statement is only satisfied if you are running a.py as a program, not importing it as a module.
So a.py should be
from b import my_variable # import the value
def run():
global x
x = my_variable.append("and another string")
print(my_variable)
run()
Note that x will be set to None because the append function does not return anything. It just appends a value to a list.
You need to call the run() function in your c.py file.
Here's how the code should be:
import a
a.run()
Well, module 'a' does have no attribute 'x'. Module 'a' has a function that creates a variable 'x', but as long as the method isn't called, the attribute isn't there.
You could change file c.py to:
import a
a.run()
print(a.x)
Another solution would be to make sure that the run() function is always called when importing module 'a'. This is currently not the case, because of the line if __name__ == '__main__':.
If you don't want to run the code but only want to make sure the variable exists, just define it in the module. Before the definition of your run() method, just add x = None (or use any other initial value you prefer).
Note, however, that there other problems with your code and that using globals in this way is a really bad programming pattern, which will likely lead to other problems later on. I wonder what you want to achieve. It probably would be a better solution if you could pass x as argument to the run() function instead of referring to a global variable. But that's outside the scope of this question and difficult to answer without more information.
I'm writing a wrapper or pipeline to create a tfrecords dataset to which I would like to supply a function to apply to the dataset.
I would like to make it possible for the user to inject a function defined in another python file which is called in my script to transform the data.
Why? The only thing the user has to do is write the function which brings his data into the right format, then the existing code does the rest.
I'm aware of the fact that I could have the user write the function in the same file and call it, or to have an import statement etc.
So as a minimal example, I would like to have file y.py
def main(argv):
# Parse args etc, let's assume it is there.
dataset = tf.data.TFRecordDataset(args.filename)
dataset = dataset.map(args.function)
# Continue with doing stuff that is independent from actual content
So what I'd like to be able to do is something like this
python y.py --func x.py my_func
And use the function defined in x.py my_func in dataset.map(...)
Is there a way to do this in python and if yes, which is the best way to do it?
Pass the name of the file as an argument to your script (and function name)
Read the file into a string, possibly extracting the given function
use Python exec() to execute the code
An example:
file = "def fun(*args): \n return args"
func = "fun(1,2,3)"
def execute(func, file):
program = file + "\nresult = " + func
local = {}
exec(program, local)
return local['result']
r = execute(func, file)
print(r)
Similar to here however we must use locals() as we are not calling exec in global scope.
Note: the use of exec is somewhat dangerous, you should be sure that the function is safe - if you are using it then its fine!
Hope this helps.
Ok so I have composed the answer myself now using the information from comments and this answer.
import importlib, inspect, sys, os
# path is given path to file, funcion_name is name of function and args are the function arguments
# Create package and module name from path
package = os.path.dirname(path).replace(os.path.sep,'.')
module_name = os.path.basename(path).split('.')[0]
# Import module and get members
module = importlib.import_module(module_name, package)
members = inspect.getmembers(module)
# Find matching function
function = [t[1] for t in members if t[0] == function_name][0]
function(args)
This exactly solves the question, since I get a callable function object which I can call, pass around, use it as a normal function.
I'm using Python 3.6, I have a file called file.py, with have this two functions:
def country(countryName):
print(countryName)
def capital(capitalName):
print(capitalName)
I need to call any of these two methods from Command Line, but sincerely I don't know how to do that, also with arguments in this way.
python file.py <method> <argument>
Does someone knows how to do that?
Greetings!
To use command line arguments in a program you can use sys.argv. Read more
import sys
def country(countryName):
print(countryName)
def capital(capitalName):
print(capitalName)
method_name = sys.argv[1]
parameter_name = sys.argv[2]
getattr(sys.modules[__name__], method_name)(parameter_name)
To run the program:
python file.py capital delhi
output:
delhi
Your input parameter method_name is a string so can't be called directly. Hence we need to fetch the method handle using getattr.
Command sys.modules[__name__] fetches the current module. which is file.py module. Then we use getattr to fetch the method we want to call and call it. we pass the parameter to the method as `(parameter_name)'
you could have a module that inspects your file.py, call it executor.py, and adjust your methods in file.py to handle argument lists
executor.py:
import file
import sys
method = file.__dict__.get(sys.argv[0])
method(sys.argv[1:-1])
Assume, I have created an python file (FirstFile.py) name which contains many functions and other things. One of the function is this (of course, it is simplified):
def func(string):
assert eval(string)
Besides, I have created an python file which imports func() from the file mentioned above. Then this second python file try to execute following process:
from FirstFile import func
amk = 1
func("amk == 1")
When variable "amk" is in the first file, no problem reveals. However, when variable "amk" is in the second file, which is illustrated here, an error reveals:
NameError: name 'amk' is not defined
Would you like to please help me solve this problem?
by default eval executes in the current local/global scope, if you want to specify a different environment you can do something like:
eval("x == 1", {"x":1})
so your function could take an optional environ argument:
def func(string, environ=None):
assert eval(string, environ)
then you can call the function from the other module passing locals() as the environment:
from FirstFile import func
amk = 1
func("amk == 1", locals())
As a side note I'd recommend against evaluating arbitrary code especially if it is coming from another source / module as it could accidentally contain harmful code.
I'm writing a program that involves callbacks called from another module, and which need to access a global variable.
It seems that changes assigned to the global variable are not seen in the callback function, which only sees the original assignment. I'm guessing due to the import from the other module.
What is the proper way to write this pattern?
First module:
# a.py
from b import runb
myGlobal=None
def init():
global myGlobal
myGlobal=1
def callback():
print myGlobal
def main():
init()
runb()
if __name__=='__main__':
main()
Second module:
#b.py
def runb():
from a import callback
callback()
I would expect this program to print '1', but instead it prints 'None'
EDIT:
init can only be called once (it is a simplification of a complex program)
Python imports the main module as __main__. When b.py imports a by its actual name, a new instance of the module is loaded under the name a. Each instance has its own myGlobal.
One solution is this:
#b.py
def runb():
from __main__ import callback
callback()
Another solution is to create a new main module. Import a there and make an explicit call to a.main().
If you do this, "from a import callback", then again "myGlobal=None" will be executed, making it to print "None"
The main() function is not called when you import the file as a module. __name__ == "main" is true only when a.py is executed directly.