How to share global variable across the files in python? - python

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.

Related

Get variable from file which is importing my function in python

I have 2 files:
Main.py
from test import test
def main():
sol = 'hello'
if test() == sol:
print('Yes')
else:
print('No')
test.py
def test():
return 'hello'
Is there a way to access the sol variable in my test function which is in another file? I'd like to do something like this:
def test():
return sol
This way it's always the same as the variable in Main.py. I tried a solution which is mentioned on Python extract variables from an imported file but it didn't work for me. Thank you for any help
Edit: I'd like to do it without changing the Main.py file
Since sol isn't defined in the function you will need to declare it as a global function so it can be used in the function. Change test.pyto the following...
test():
global sol
return sol
Hope that helps.
If sol is a constant (i.e. a variable which will not change during the course of the program), then you can put it into a separate file, say var.py, and import it into both main.py and test.py:
from var import sol
BUT what you will be importing is a copy of the variable with the value it had at the time it was imported - any subsequent reassignments will not update the value of sol in test.py and main.py. Because a string is immutable, when you reassign a value to it what you are actually doing is you are reusing the variable name for a new entity.
What you need to do is have your variable in a mutable structure, such as a list or a class, so your var.py will look like this:
class v(object):
sol = 'Hello'
and then in main.py and test.py you can refer to sol using:
from var import v
print(v.sol)
This way, any changes to v.sol will be correctly reflected anywhere class v is imported. A bit cumbersome, but that's how it is in Python.
You can use inspect module to get the sol variable from main function without change anything of main.py. Of course, you need to call main function.
Main.py:
from test import test
def main():
sol = 'hello'
if test() == sol:
print('Yes')
else:
print('No')
main()
test.py:
import inspect
def test():
frame = inspect.currentframe()
sol_from_main = 'default'
try:
sol_from_main = frame.f_back.f_locals['sol'] # line A
except:
print('No sol found')
print(sol_from_main) # this print 'hello'
return sol_from_main
Output:
hello
Yes
Explanation:
From the python doc, we can see next:
frame
f_back | next outer frame object (this frame’s caller)
f_locals | local namespace seen by this frame
So line A get the caller of current function, that is main function, and use f_locals to get all local variables of main function, so it can get the sol value from main. FYI in case you still need it.

How to use a function containing eval in a file by variable defined at another file from that another file?

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.

Python global variables and callbacks

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.

Declaration functions in python after call

$ cat declare_funcs.py
#!/usr/bin/python3
def declared_after():
print("good declared after")
declared_after()
$ python3 declare_funcs.py
good declared after
Change call place:
$ cat declare_funcs.py
#!/usr/bin/python3
declared_after()
def declared_after():
print("good declared after")
$ python3 declare_funcs.py
Traceback (most recent call last):
File "declare_funcs.py", line 4, in <module>
declared_after()
NameError: name 'declared_after' is not defined
Is there way to declare only header of function like it was in C/C++?
For example:
#!/usr/bin/python3
def declared_after() # declaration about defined function
declared_after()
def declared_after():
print("good declared after")
I found this Declare function at end of file in Python
Any way there appear another function in the beginning like wrapper, and this wrapper must be called after declaration of wrapped function, this is not an exit. Is there more elegant true-python way?
You can't forward-declare functions in Python. It doesn't make a lot of sense to do so, because Python is dynamically typed. You could do something silly like this, and what would expect it to do?
foo = 3
foo()
def foo():
print "bar"
Obviously, you are trying to __call__ the int object for 3. It's absolutely silly.
You ask if you can forward-declare like in C/C++. Well, you typically don't run C through an interpreter. However, although Python is compiled to bytecode, the python3 program is an interpreter.
Forward declaration in a compiled language makes sense because you are simply establishing a symbol and its type, and the compiler can run through the code several times to make sense of it. When you use an interpreter, however, you typically can't have that luxury, because you would have to run through the rest of the code to find the meaning of that forward declaration, and run through it again after having done that.
You can, of course, do something like this:
foo = lambda: None
foo()
def foo():
print "bar"
But you instantiated foo nonetheless. Everything has to point to an actual, existing object in Python.
This doesn't apply to def or class statements, though. These create a function or class object, but they don't execute the code inside yet. So, you have time to instantiate things inside them before their code runs.
def foo():
print bar()
# calling foo() won't work yet because you haven't defined bar()
def bar():
return "bar"
# now it will work
The difference was that you simply created function objects with the variable names foo and bar representing them respectively. You can now refer to these objects by those variable names.
With regard to the way that Python is typically interpreted (in CPython) you should make sure that you execute no code in your modules unless they are being run as the main program or unless you want them to do something when being imported (a rare, but valid case). You should do the following:
Put code meant to be executed into function and class definitions.
Unless the code only makes sense to be executed in the main program, put it in another module.
Use if __name__ == "__main__": to create a block of code which will only execute if the program is the main program.
In fact, you should do the third in all of your modules. You can simply write this at the bottom of every file which you don't want to be run as a main program:
if __name__ = "__main__":
pass
This prevents anything from happening if the module is imported.
Python doesn't work that way. The def is executed in sequence, top-to-bottom, with the remainder of the file's contents. You cannot call something before it is defined as a callable (e.g. a function), and even if you had a stand-in callable, it would not contain the code you are looking for.
This, of course, doesn't mean the code isn't compiled before execution begins—in fact, it is. But it is when the def is executed that declared_after is actually assigned the code within the def block, and not before.
Any tricks you pull to sort-of achieve your desired effect must have the effect of delaying the call to declared_after() until after it is defined, for example, by enclosing it in another def block that is itself called later.
One thing you can do is enclose everything in a main function:
def main():
declared_after()
def declared_after():
print("good declared after")
main()
However, the point still stands that the function must be defined prior to calling. This only works because main is called AFTER declared_after is defined.
As zigg wrote, Python files are executed in order they are written from top to bottom, so even if you could “declare” the variable before, the actual function body would only get there after the function was called.
The usual way to solve this is to just have a main function where all your standard execution stuff happens:
def main ():
# do stuff
declared_after();
def declared_after():
pass
main()
You can then also combine this with the __name__ == '__main__' idiom to make the function only execute when you are executing the module directly:
def main ():
# do stuff
declared_after();
def declared_after():
pass
if __name__ == '__main__':
main()

How to import another external python module?

this is probably a dumb question, but wasnt too sure what else to do.
main.py
import module2
global x
hello="Hello"
x=module2.message()
x.say()
module2.py
class message:
def say():
print hello
When I print hello, i am referring to the hello variable in main.py however this method will return an error. Does anyone know the solution? (i would prefer not to pipe the hello variable into the function)
The only reliable solution is called encapsulation.
So, basically, you could change your code to look like that:
main.py
import module2
global x
hello="Hello"
x=module2.message(hello)
x.say()
module2.py
class message:
def __init__(self, hello):
self.hello = hello
def say():
print self.hello
Plus try to follow coding style of Python - life of you and future developers of your code will be easier.
Multiple options, but do note that one module cannot ever access the calling module directly.
Simply pass hello as a variable (def say(msg): print msg)
Pass all variables in main.py to module2: def say(g): print g['hello'] and say(globals())
Store it somewhere, then extract it when you need it.
Since main.py imports module2.py, you can access the globals defined in moule2 in main.
In your case since module2 is not importing main, so the globals in main is not accessed in module2.
one solution is that defined by #Tadeck
In this particular example, it's totally OK for module2.py to import main.py, there are some gotcha's though.
The most obvious is that main.py is probably being run from the command line, like python main.py, which has the effect of making that file think it's called __main__. You could import that module in module2, but that's sort of unusual; it's called "main.py" and you want to import main. Doing so will cause the module to be imported a second time.
For that to be OK, you have to arrange for importing the file to have no side effects unless it's imported as __main__. A very common idiom in python is to test that condition at the end of a module.
import module2
global x
hello="Hello"
def main():
x=module2.message()
x.say()
if __name__ == '__main__':
main()
And now it's just fine for module2.py to actually import main. On the other hand, importing variables from one module into another gets hard to predict when the imports can be recursive, you may not have that variable yet because the module is already trying to import you. On the other hand, it's always safe to refer to a variable in a module using dotted syntax. So your module2.py should be:
import main
class message:
def say():
print main.hello
which also makes it more obvious just where hello came from.

Categories

Resources