Sharing Global variables in python - python

I have 2 files a.py and b.py as follows:
a.py
import b.py
Test="abc"
def main(args):
global Test
if args.target=="this":
Test="klm"
b.fun()
#rest of the body which I intend to execute only once
#hence I cannot call main() again
if __name__ == "__main__":
#some arguments are parsed
args = parser.parse_args()
main(args)
b.py
import a
print a.Test
EDIT: Output:
python a.py
abc
So basically my question is why is the Test variable not getting updated in b.py and how can I make this work? Thanks.

import a
a.main()
print a.Test
a.Test = "new Value"
print a.Text
You never invoke the main function. When you import a module, __name__ is not "__main__", so your main() never runs. When you run a.py directly it will run main()

Added due to question edit:
You need to consider the ordering of the imports execution. Consider these working files.
a.py
print("Entering a")
import argparse
import b
Test="abc"
print("Id of Test: ", id(Test))
def main(args):
global Test
if args.target=="this":
Test="klm"
b.fun()
#rest of the body which I intend to execute only once
#hence I cannot call main() again
if __name__ == "__main__":
#some arguments are parsed
print('Entering main')
parser = argparse.ArgumentParser()
parser.add_argument('--target', dest='target', type=str)
args = parser.parse_args()
main(args)
b.py
print("Entering b")
import a
print a.Test
def fun():
pass
The console produces the following:
$ python a.py
Entering a
Entering b
Entering a
('Id of Test: ', 40012016L)
abc
('Id of Test: ', 40012016L)
Entering main
The problem is, when you import a python module/file, you will immediately execute all the statements in that module. As such, you have a problem with your dependencies (aka imports), because b is importing a before the value of Test is 'corrected' and then immediately acting on this.
Consider two changes. First, introduce a third file config.py that contains this configuration information and that b does not import a. Second, move all your statements that require this config in b into functions that are called/bootstrapped by a, as obviously intended.
Previous answer:
I have a solution demonstrating the issue, by only modifying b.py
def fun(): # Added because your main calls this. An error?
pass
from a import Test, main
import a
print Test # prints 'abc'
print a.Test # prints 'abc'
main()
print Test # prints 'abc'
print a.Test # prints 'klm'
Within the python interpretor, I can produce the following:
>>> import b
abc
abc
abc
klm
In your code, you create a new variable called Test with the command from a import Test that points to the original string object. You actually want to access the Test variable owned by the module a.

In a.py you run main in the if statement:
if __name__ == "__main__":
main()
Only executes main() if that is the main script. When you import the module all the code in the if block is not run because it is not the main script. To have the main method be called remove the if statement or just call main in b.py.

Related

Python relative import variable name error [duplicate]

I created two files, and when I run a.py, result is {'1': '1'}, it's correct. however, running b.py, the result is none. How can I get the value of requests from b.py?
a.py:
requests = {}
def set_value():
global requests
requests["1"] = "1"
if __name__ == "__main__":
set_value()
print(requests)
b.py:
import a
def get_value():
print(a.requests)
if __name__ == "__main__":
get_value()
if __name__ == "__main__": means that the code following it will only be executed when the file is called explicitly with python3 filename.py from the command line. Since you are simply importing your file and not executing it, the global variable is never set.
Also, python variables are all "global" variables when declared outside of a function, and the global keyword is only needed when you want to declare a global variable inside of a function.
To fix this, change a.py to the following:
requests = {}
def set_vale():
requests["1"] = "1"
set_vale()

How to change and save variable in different files

I have three python files:
a.py
theVariable = "Hello!"
b.py
import a
a.theVariable = "Change"
c.py
import a
while True:
print(a.theVariable)
I want c.py to print out "Change" instead of "Hello!". How can I do this and why wont this work?
There needs to be separate files because b.py would be running a Tkinter gui.
You can use classes to get an instance variable which holds some state
a.py
class Foo():
def __init__(self):
self.greeting = "Hello"
And create functions so that you can defer actions on references
b.py
def changer(f):
f.greeting = "Change"
When you import a class and then pass it to a function, you are passing a reference to something that can change state
c.py
from a import Foo
from b import changer
a = Foo()
for x in range(10): # simple example
if x > 5:
changer(a)
print(a.greeting)
a.py
theVariable = "Hello!"
def change(variable):
theVariable = variable
b.py
import a
change('change')
c.py
import a
while True:
print(theVariable)
i've been working with PyQt recently and this worked fine. setting a function in the orgin .py file makes it much simpler.

how can I access a global variable from another .py file in python?

I created two files, and when I run a.py, result is {'1': '1'}, it's correct. however, running b.py, the result is none. How can I get the value of requests from b.py?
a.py:
requests = {}
def set_value():
global requests
requests["1"] = "1"
if __name__ == "__main__":
set_value()
print(requests)
b.py:
import a
def get_value():
print(a.requests)
if __name__ == "__main__":
get_value()
if __name__ == "__main__": means that the code following it will only be executed when the file is called explicitly with python3 filename.py from the command line. Since you are simply importing your file and not executing it, the global variable is never set.
Also, python variables are all "global" variables when declared outside of a function, and the global keyword is only needed when you want to declare a global variable inside of a function.
To fix this, change a.py to the following:
requests = {}
def set_vale():
requests["1"] = "1"
set_vale()

if __name__ == '__main__' function call

I am trying to work around a problem I have encountered in a piece of code I need to build on. I have a python module that I need to be able to import and pass arguments that will then be parsed by the main module. What I have been given looks like this:
#main.py
if __name__ == '__main__'
sys.argv[] #pass arguments if given and whatnot
Do stuff...
What I need is to add a main() function that can take argument(s) and parse them and then pass them on like so:
#main.py with def main()
def main(args):
#parse args
return args
if __name__ == '__main__':
sys.argv[] #pass arguments if given and whatnot
main(sys.argv)
Do stuff...
To sum up: I need to import main.py and pass in arguments that are parsed by the main() function and then give the returned information to the if __name_ == '__main_' part.
EDIT
To clarify what I am doing
#hello_main.py
import main.py
print(main.main("Hello, main"))
ALSO I want to still be able to call main.py from shell via
$: python main.py "Hello, main"
Thus preserving the name == main
Is what I am asking even possible? I have been spending the better part of today researching this issue because I would like to, if at all possible, preserve the main.py module that I have been given.
Thanks,
dmg
Within a module file you can write if __name__ == "__main__" to get specific behaviour when calling that file directly, e.g. via shell:
#mymodule.py
import sys
def func(args):
return 2*args
#This only happens when mymodule.py is called directly:
if __name__ == "__main__":
double_args = func(sys.argv)
print("In mymodule:",double_args)
One can then still use the function when importing to another file:
#test.py
import mymodule
print("In test:",mymodule.func("test "))
Thus, calling python test.py will result in "In test: test test ", while calling python mymodule.py hello will result in "In mymodule: hello hello ".

Python equivalent of Ruby `if __FILE__ == $PROGRAM_NAME`

In Ruby, you can write a class/module such that it can be (a) loaded into an interactive Ruby terminal without actually executing code, or (b) run as a shell script.
For example, given file foo.rb:
class Foo
def bar
puts 'Foo bar'
end
end
if __FILE__ == $PROGRAM_NAME
foo = Foo.new
foo.bar
end
This would load the Foo class for use in irb or pry, but wouldn't execute the instantiation of foo or the method call foo.bar inside the if statement at the end.
But if run in the command line with ruby foo.bar it would return "Foo bar" and exit.
Is there a Python (v2 or v3) equivalent of this?
The closest I've come (in 2.7) is this, but I feel like there might be a cleaner way:
import os, sys
if os.__file__ == sys.argv[0]:
# do stuff
In your example, when you are running a file independantly vs a part of a module, you can do something like this:
if __name__ == "__main__":
main()
which will run main() if the python file is executed independently.
In your example, you would likely want something like this.
class Foo:
def bar(self):
print 'Foo bar'
def main():
foo = Foo()
foo.bar()
if __name__ == "__main__":
main()
I personally like to define a main function as the above example, but could easily just do:
if __name__ == "__main__":
foo = Foo()
foo.bar()
Python modules include a __name__ variable holding the module name. If its the top level script, the name is __main__.
class Foo:
def bar(self):
print('Foo bar')
if __name__ == "__main__":
foo = Foo()
foo.bar()

Categories

Resources