Using global variables in Python modules - python

I have these 4 modules
globals.py
globvara = "a"
mod1.py
from globals import *
print globvara
output : a
mod2.py
from mod1 import *
def changegv(newval1):
#global globvara
globvara = newval1
def usechangegv(newval2):
changegv(newval2)
and mod3.py
from mod2 import *
usechangegv("b")
print globvara
output :
a
a
I am wondering why the globalvar does not change in module 2. I am missing something in global variables. Even if I uncomment the global globvara line I get the same result. Where is the error?

Python global variables are global only to modules. When you import a variable from another module (e.g. from mod1 import *), Python creates duplicate references to the value in the importing module. So you now have two names, mod1.globvara and mod2.globvara, which initially point to the same value, but which are not in any way connected. If you change globvara in mod2.py, you are changing mod2.globvara and mod1.globvara is not affected.
To avoid this problem, import the module, not the individual names defined in it. For example, import globals. Then always refer to globals.globvara (or better yet, globals.a). Since you are always accessing and assigning the same name, it will work the way you expect.

Don't use the
from <module> import <variable>
As it creates a copy of the variable.
Do a simple:
import <module>
And all accesses to the global variable should use the "variable" within "module":
<module>.<variable> = ...
or
print <module>.<variable>

Related

Why global value doesn't change when reading from another module?

I have three files:
globals.py:
value = None
reader.py:
from globals import *
def read_global():
print(value)
changer.py:
from globals import *
from reader import *
def change_global():
global value
value = 1
change_global()
read_global()
I would expect the call to "read_global" would print 1, but the value None is printed.
Why is that the case? Why the new value set in "change_global" doesn't print?
Change your import into
changer.py:
from reader import *
import globals as g
def change_global():
g.value = 1
change_global()
read_global()
print(g.value)
reader.py:
import globals as g
def read_global():
print(g.value)
globals.py:
value = None
I think when you call value in the change_global function you are not calling the global variable you declare in global.py but creating new local variable inside the function so when you set the import alias into g will make sure you call/set the right one (variable)
I've been reading about modules in the Python documentation and it states:
Each module has its own private symbol table, which is used as the global symbol table by all functions defined in the module. Thus, the author of a module can use global variables in the module without worrying about accidental clashes with a user’s global variables. On the other hand, if you know what you are doing you can touch a module’s global variables with the same notation used to refer to its functions, modname.itemname.
This implicates that the global symbol table is not shared between modules.

What is the difference between import X and from X import *

The common explanation given (as in 12270954 and 710551) is that from X import *
clutters up the namespace, and hence is not recommended. However, the following example
shows that there is something more to it than just cluttering the namespace.
Consider the following code:
x1.py:
g_c = 5
class TestClass():
def run(self):
global g_c
g_c = 1
print(g_c) # prints 1
x2.py:
from x1 import *
t = TestClass()
t.run()
print(g_c) # prints 5, why?
x3.py:
import x1
t = x1.TestClass()
t.run()
print(x1.g_c) # prints 1
The results for running x2.py and x3.py are different (on python 3.6.8). Can someone please explain why
the two imports are behaving differently?
Extra Notes: (to demonstrate the note mentioned by #tdelaney about lists)
Change the assignments in x1.py like this:
g_c = [5]
...
g_c.append(1)
And now, both x2.py and x3.py give the same answer. It is only when an atomic type is being used that the problem arises.
You can imagine from x1 import * doing something approximately equal to
import m1
globals.update(m1.__dict__)
del m1
In other words it imports the module and then copies all the globals into your namespace. The function and classes inside the module however will keep referring to their original globals, not to the copies in your namespace.
Note the "implementation" above is not completely correct as not all names are copied and there are other subtleties, but it's I think an easy way to understand the general behavior.
The difference becomes evident when the module changes its globals but you don't see the change reflected in your global namespace.
After executing from x1 import * the variables sys.modules["x1"].g_c and g_c are two distinct variables with the same value; code in the module is referring to the one inside the module, not to your copy.
from X import * rebinds the objects in X's global namespace to the current module's namespace. If one of these variables is reassigned, the reassignment is private to the current namespace.
The import doesn't change the imported objects, though, it just adds a new reference. So for instance, the global namespace for class TestClass is still the x1.py module. TestClass.run always changes x1.g_c (its global namespace) regardless of which module calls it.
In x2.py, you import the original 5 referenced by x1.g_c to x2.g_c. But reassignment of x1.g_c doesn't affect x2.g_c which is a variable in a different namespace.
Suppose conversely that x1.g_c was a list and your code was appending to the list. In that case, all modules would see the appends because you are modifying the object referenced by x1.g_c, not reassigning it.
When you import X, you will have to use X to call a function inside X, ie:
X.func1()
But when you use from X import *, you import all names in the module's namespace that don't begin with _ or all names in module.__all__ , and you don't require to use X to call the function, ie:
func1()
In x2.py when you did:
from x1 import *
you just imported every thing from x1 , ie , including the variables. This means that your altered the namespace of the current script (x2). So when you call:
print(g_c)
it prints :
5
which is called from the current scripts namespace.
On the run of the class TestClass() in x2 , it changed the value of g_c in x1, but not in x2.
This indicates the Disadvantages of using Global Variables.
When variables are declared as global, then they remain in the memory till program execution is completed. That is, your global declaration is only valid inside x1. The declaration is valid inside x1's namespace.
And when you did:
import x1
t = x1.TestClass()
t.run()
This import x1 as a module and everything inside isin't imported unless you call it. And you did call the class TestClass(), ran it, resulting g_c inside the class being made a global variable. So then for x1, g_c is 1 since it was globally defined and the current script doesn't know x1 has a g_c = 5 since it wasn't imported/called.
On print(x1.g_c), it calls for the value of g_c in x1's namespace, which is 1.
The keys of this behavior is following:
Python makes namespaces for each files
global X makes variable X refer to the object that lives in the namespace where global X is declared
When t.run() is executed in x2.py, global g_c is evaluated and this makes g_c refers to the object in the namespace for x1.py not x2.py.
Trying the following snippet would be help.
x2_.py
from x1 import *
t = TestClass()
t.run()
print(g_c) # prints 5
import x1
print(x1.g_c) # this print 1
Let us take an example where you are importing the module suman in Python. It brings the entire module into your workspace i.e. In the import suman statement it does not give you access to any methods or function associated with like for example if their is a function display_name() in the suman module then you have to import it like suman.display_name()
In from suman import * it brings all of the names inside suman module (like display() for example) into your module. Now you can access those names without a prefix of name of your module like this:
from suman import *
print(display_name())

Concept of namespace, global, local with respect to import

I understand that below are the scoping levels in python (listed in highest to lowest order)
Local(L): Defined inside function/class
Enclosed(E): Defined inside enclosing functions(Nested function concept)
Global(G): Defined at the uppermost level
Built-in(B): Reserved names in Python builtin modules
I understand this concept when we have a single file. I am trying to understand how this concept of namespace, local, enclosed, global, built-in works when using import in python.
I understand we can import using foll. approaches:
import modulename
import modulename.function(function/variable)
import package.module.function(function/variable)
from module import function(function/variable)
from package import module
from package.module import function(function/variable)
from module import *
from package import *
I know that in each of the above the entire module is loaded in the sys modules dictionary. But I am confused with respect to namespace, scope, global, local. I want to understand LEGB principle, namespace, global, localwith respect to the method of import vs from import. I have read that in case of point 1 (import modulename), the modulename is loaded in its own namespace and reference is available to the calling module with which it can change the variable values globally. Does this also mean it is in global namespace? Any if so then global with respect to what? Also I have read that from module import function/variable or from module import * brings function(s)/variable(s) in the calling modules namespace and any changes are not global. Does this mean that it is in local namespace? Local with respect to what?
Example:
Say module foo has a variable bar=10. When we use [import foo] - this brings foo in current namespace and allows us to change the value of bar via foo.bar=1000 and this change is visible to every piece of code that makes use of [import foo print(foo.bar)] after the above assignment was made. Where as in case of [from foo import bar], any change made to bar is only visible to this module and not any other module irrespective of whether they do an [import foo] or [from foo import bar] they would see value of bar as 10.
Any reference/links in this area will be very helpful. I want to understand the basics of how this works internally. Any information will be helpful to understand this. Articles that I found on this topic explain what is import vs from xx import yy. But they don't explain why/how the changes made become global (in case of import) vs local (in case of from import).
Some more examples:
In below code example, change made to a is only seen in the main.py file and does not affect the value of a in module1.py and subsequent modules that import module1.py will still see the value of a as 10.
module1.py:
a=10
main.py:
from module1 import a
print(a)
a=100
Whereas if we used import module1 instead of from module1 import a then the assignment would have changed value of a in module1.py and any subsequent import of module1.py would show the value of a as 100.
Note: Similarly we could also have functions inside the module.py that get and set the value of variable a. And using this approach, once we do a from module1 import getfn, setfn in main.py, we can use these functions which when called make the change to variable a and this change is globally visible.
You're over complicating things. From the point of view of imports, the only thing to know is that import foo brings foo into the current namespace, and from foo import bar brings bar into the current namespace.
Python has only 3 scopes: global local and builtin.
They are relative to the position in the code
Every variable whose value you can change is local
(note that changing global variable results in creating a new local variable instead,
so there are local and global variable of the same name)
Enclosed you speak of are local to that function
Every variable with unchangeable content whose value you can get is global
Builtin variables are exactly like global so they can even be considered global
to see what variables are global and what are local, put this line in your code
print("global:", globals(), "\n\nlocal:", locals())

Can I access a module object if it has only been imported via "from module import *"?

I have files that define global variables which I would like to use outside of the files, e.g. "func.py" containing:
def init():
global a
a = 5
If I import via "from x import *", then accessing the module's global variables like this does not work:
from func import *
init()
a
func.a
as neither a nor func are defined. "func" is listed in sys.modules.keys(), however.
I know "from x import *" is not exactly best practice, but how can I access the module's variables or the module object when using it?
I haven't found a way to do this other than importing the module "properly" as well.
import func
from func import *
init()
func.a
This question is very closely related. This one implies that since modules are imported fully with either command, there is no real performance difference either. This suggestion to use a separate file/container with global variables for larger projects is worth mentioning, too.
And obviously, don't use "from x import *" outside of live troubleshooting if you can't help it.

Understanding global variable in Python

I came across a strange issue in Python when using global variables.
I have two modules(files):mod1.py and mod2.py
mod1 tries to modify the global variable var defined in mod2. But the var in mod2 and var in mod seems to be two different things. Thus, the result shows that such modification does not work.
Here is the code:
#code for mod2.py
global var
var = 1
def fun_of_mod2():
print var
#code for mod1.py
from mod2 import var,fun_of_mod2
global var #commenting out this line yields the same result
var = 2 #I want to modify the value of var defined in mod2
fun_of_mod2() #but it prints: 1 instead of 2. Modification failed :-(
Any hint on why this happens? And how can I modify the value of val defined in mod2 in mod1?
Thanks
When you import var into mod1:
from mod2 import var,fun_of_mod2
You are giving it the name var in mod1's namespace. It is as if you did this:
import mod2
var = mod2.var
fun_of_mod2 = mod2.fun_of_mod2
del mod2
In other words, there are now two names for the value, mod1.var and mod2.var. They are the same at first, but when you reassign mod1.var, mod2.var still points to the same thing.
What you want to do is just:
import mod2
Then access and assign the variable as mod2.var.
It's important to note that global variables in Python are not truly global. They are global only to the module they're declared in. To access global variables inside another module, you use the module.variable syntax. The global statement can be used inside a function to allow a module-global name to be assigned to (without it, assigning to a variable makes it a local variable in that function). It has no other effect.

Categories

Resources