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.
Related
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())
I want to use a config.py file in which I will be declaring some constants to be used in mainFile.py.
I'll be defining these "constant variables" using Capital letters.
I want to make it easier to configure the mainFile.py parameters by defining the constants only in config.py.
Ofcourse, in mainFile.py, the values of these constant are by no means altered.
So, my question is :
If in mainFile.py I use "From config.py import *", are the "constant variables" defined in config.py used as global variables in mainFile.py?
E.g. inn functions defined within mainFile.py, do I need to re-define these variables as global in order to use them?
You can simply write import config, and all of your constants will be accessible to your code in mainFile.py.
There are two options:
As already pointed out by #Josh, in config.py you name your variables, such as m=10, t=52, and so on. Then on mainFile.py you import config and access your variables as config.m that will result in 10. Like:
y = config.m
y = 10
The second option is a bit longer. You create a function such as
def m():
m = 10
return m
Then on mainFile.py you import config and access the variable as config.m() that will yield 10. Like
z = config.m()
z = 10
global is required if you are modifying the imported variable in some case and you need to reflect that value on all other places where the variable is being accessed.
since you are just reading the value of the imported variable here, global is no required. also inside functions if any variable is read first it searches on local scope then on global scope. So no global required inside function for reading purpose.
I have a directory structure like this:
home/
main.py
lib/
mylib/
Textfile_Class.py
Excelfile_Class.py
globals.py (has all the global variables declared here)
functions.py
I created an object of Textfile_class in main.py using
txt = TEXT(file).
Now, I want to use this variable txt during creating object of Excelfile_Class for some operations (eg, if the value of a variable in txt object is 5, then do certain action in Excelfile_Class )
In Excelfile_Class, I am also importing all the global variables. String variables are accessible there but I dont know why this object txt is not accessible there. Wherever I am refering to txt in Excelfile_Class(self.line_count = txt.count), I am getting below error: AttributeError: 'NoneType' object has no attribute 'count'
Please help me to know why this is happening even though I have defined all the variables in a seperate file and importing those in all the files.
Eg:
main.py
path = os.path.abspath('./lib')
sys.path.insert(0, path)
from mylib.Textfile_class import *
from mylib.Excelfile_Class import *
from mylib.globals import *
from mylib.functions import *
if __name__ == "__main__":
txt = TEXT(file)
xcel = EXCEL(file)
Eg globals.py
global txt, xcel
txt=None
xcel=None
Eg Textfile_class.py
from globals import *
class TEXT:
def __init__(self, filename):
self.count = 0
with open(filename) as fp:
for line in fp:
self.count = self.count + 1`
Eg Excelfile_Class.py
from globals import *
class EXCEL:
def __init__(self, filename):
self.line_count = 0
self.operation(filename)
def operation(self, file):
self.line_count = txt.count
if self.line_count:
self.some_operation()
else:
self.other_operation()
When you assign a value to a variable name inside a function, you're not working with the global version of the variable any more, instead you have a completely new variable.
You have to use global keyword inside the function to indicate you're working with a global variable.
From Python Doc FAQ
What are the rules for local and global variables in Python?
In Python, variables that are only referenced inside a function are implicitly global. If a variable is assigned a new value anywhere within the function’s body, it’s assumed to be a local. If a variable is ever assigned a new value inside the function, the variable is implicitly local, and you need to explicitly declare it as ‘global’.
Read more...
Example:
x = None # x is momdule-level global variable
def local():
x = 5 # assign 5 to x, here x is a new variable, global x is not affected.
def glob():
global x # indicate we'll working with the global x.
x = 5 # this affect the global variable.
def print_global():
print(x) # Just print the global variable.
local()
print_global() # Prints None
glob()
print_global() # Prints 5
So, every time you refer to txt inside a function, you have to tell the context you'll be working with the global version of txt.
Other thing can be happening!
Python is interpreted, that means it execute the code line by line, if in the others modules (not in the main module) you have code trying to access txt before some value be assigned
if __name__ == "__main__":
txt = TEXT(file)
, then you'll get the same error.
A recommendation:
Try to avoid the use of global variables, you already know that isn't a good practice and it leads to unestable code.
If your problem is that you want to txt and xcel to be available at any time anywhere, you could use the pattern Singleton (warning, Singleton is considered an anti-pattern ref)
I will post an example for you, but before I will encorage you to redesign your program, I ensure you it will be a good exercise!
Singleton example: (again this is an anti-pattern, but I preffer it to nude global variables).
class Globals(object):
__instance = None
def __init__(self):
class wrapped_class:
def __init__(self):
self.txt = None
self.excel = None
if (Globals.__instance is None):
Globals.__instance = wrapped_class()
def __getattr__(self, attrname):
return getattr(self.__instance, attrname)
def __setattr__(self, attrname, value):
setattr(self.__instance, attrname, value)
glob = Globals() # Since __instance is None this will instantiate wrapped_class and save the reference in __instance
glob.txt = "Txt example" # Modify the txt attribute of __instance.
glob_1 = Globals() # Since __instance is not None it stays as it is.
print(glob.txt) # Prints "Txt example"
print(glob_1.txt) # Prints "Txt example"
It is quite hard to tell where your problem is without having the code or the stack trace but I would strongly advice that you read some documentation about Python best practices, the use of global variables and naming conventions. This by itself might solve your issues.
Naming conventions might sound silly but those things and other syntax-related choices do matter in python.
Also, you seem to be missing __init__.py file in your module which may or may not be important depending of the python version you are using.
Here are a few links to get you started:
https://www.python.org/dev/peps/pep-0008/#naming-conventions
https://docs.python.org/2/tutorial/classes.html#private-variables-and-class-local-references
http://www.python-course.eu/global_vs_local_variables.php
http://gettingstartedwithpython.blogspot.be/2012/05/variable-scope.html
http://c2.com/cgi/wiki?GlobalVariablesAreBad
I dont know why it happened like that. If anyone knows they can tell.
The problem got resolved when I used the method given in Using global variables between files in Python.
So, finally I put all the global variables in a function in globals.py and instantiated that once in main.py. Then, I used from mylib import globals and referenced the global variables inside the classes as globals.txt and it worked fine.
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>
first.py
myGlobal = "hello"
def changeGlobal():
myGlobal="bye"
second.py
from first import *
changeGlobal()
print myGlobal
The output I get is
hello
although I thought it should be
bye
Why doesn't the global variable myGlobal changes after the call to the changeGlobal() function?
Try:
def changeGlobal():
global myGlobal
myGlobal = "bye"
Actually, that doesn't work either. When you import *, you create a new local module global myGlobal that is immune to the change you intend (as long as you're not mutating the variable, see below). You can use this instead:
import nice
nice.changeGlobal()
print nice.myGlobal
Or:
myGlobal = "hello"
def changeGlobal():
global myGlobal
myGlobal="bye"
changeGlobal()
However, if your global is a mutable container, you're now holding a reference to a mutable and are able to see changes done to it:
myGlobal = ["hello"]
def changeGlobal():
myGlobal[0] = "bye"
I had once the same concern as yours and reading the following section from Norman Matloff's Quick and Painless Python Tutorial was really a good help. Here is what you need to understand (copied from Matloff's book):
Python does not truly allow global variables in the sense that C/C++ do. An imported Python module will not have direct access to the globals in the module which imports it, nor vice versa.
For instance, consider these two files, x.py,
# x.py
import y
def f():
global x
x = 6
def main():
global x
x = 3
f()
y.g()
if __name__ == ’__main__’:
main()
and y.py:
# y.py
def g():
global x
x += 1
The variable x in x.py is visible throughout the module x.py, but not in y.py. In fact, execution of the line
x += 1
in the latter will cause an error message to appear, “global name ’x’ is not defined.”
Indeed, a global variable in a module is merely an attribute (i.e. a member entity) of that module, similar to a class variable’s role within a class. When module B is imported by module A, B’s namespace is copied to A’s. If module B has a global variable X, then module A will create a variable of that name, whose initial value is whatever module B had for its variable of that name at the time of importing. But changes to X in one of the modules will NOT be reflected in the other.
Say X does change in B, but we want code in A to be able to get the latest value of X in B. We can do that by including a function, say named GetX() in B. Assuming that A imported everything from B, then A will get a function GetX() which is a copy of B’s function of that name, and whose sole purpose is to return the value of X. Unless B changes that function (which is possible, e.g. functions may be assigned), the functions in the two modules will always be the same, and thus A can use its function to get the value of X in B.
Python global variables are not global
As wassimans points out above they are essentially attributes within the scope of the module they are defined in (or the module that contains the function that defined them).
The first confusion(bug) people run into is not realizing that functions have a local name space and that setting a variable in a function makes it a local to the function even when they intended for it to change a (global) variable of the same name in the enclosing module. (declaring the name
in a 'global' statement in the function, or accessing the (global) variable before setting it.)
The second confusion(bug) people run into is that each module (ie imported file) contains its own so called 'global' name space. I guess python things the world(globe) is the module -- perhaps we are looking for 'universal' variables that span more than one globe.
The third confusion (that I'm starting to understand now) is where are the 'globals' in the __main__ module? Ie if you start python from the command line in interactive mode, or if you invoke python script (type the name of the foo.py from the command shell) -- there is no import of a module whose name you can use.
The contents of 'globals()' or globals().keys() -- which gives you a list of the globals -- seems to be accessible as: dir(sys.modules['__main__'])
It seems that the module for the loaded python script (or the interactive session with no loaded script), the one named in: __name__, has no global name, but is accessible as the module whose name is '__main__' in the system's list of all active modules, sys.modules