using global variable in python among modules in different packages - python

I'm new to Python and am trying to use a global counter from a module in a package in different modules in different packages. What I want to do is declare a variable in a module and import it to other modules in different packages. I made a simple test for the question and it's happening here too. I made all files in a same directory(they are now in the same package but the problem is the same).
file glbcntmod.py :
glbcnt = 0
file glbfuncmod.py :
from glbcntmod import glbcnt
def glbfunc():
global glbcnt
print 'glbcnt = ',glbcnt
file : test.py
#!/usr/bin/env python
from glbcntmod import glbcnt
from glbfuncmod import glbfunc
loccnt = 0
def localfunc():
print 'loccnt = ',loccnt
if __name__ == '__main__':
glbcnt = 0
for i in xrange(0,4):
glbfunc()
localfunc()
glbcnt += 1
loccnt += 1
When I run test.py, the result is like below. loccnt is incrementing but glbcnt is always 0. What is the problem?
glbcnt = 0
loccnt = 0
glbcnt = 0
loccnt = 1
glbcnt = 0
loccnt = 2
glbcnt = 0
loccnt = 3

The way to do this is to keep the module where the variable is as a reference:
import other_module
other_module.counter += 1
If you do that everywhere you use counter it will have a consitent value across modules.
That happens because each time you do an assignment to a name in Python, the object associated with that name changes -
That is, if you do
from othermodule import counter
counter = 1
Your counter variable will point to a different object from that assignment on. And since numbers are immutable objects, there are even other problems with that.
But f you keep the original module around, you are changing an attribute in that module object - which behaves exactly like any other Python object. As long as other code access the variable as an attribute of the module, you are good.

Note that int is immutable in python. That means doing something like
a = 0
b = a # b = 0
b += 1 # b = 2
will still leave a as 0.
When you do from glbcntmod import glbcnt, this basically equals
import glbcntmod
glbcnt = glbcntmod.glbcnt
So, if you then increment glbcnt, only the local name will be assigned the new value. The original glbcnt is not changed.
If you want to use a global variable, you must use its global name. So what you want to work with and modify is glbcntmod.glbcnt.

If you're trying to update a global variable from another module, check this answer out: https://stackoverflow.com/a/15595447/3224629

In test.py:
if __name__ == '__main__':
glbcnt = 0
for i in xrange(0,4):
...
glbcnt += 1
You make a local glbcnt variable here, which is the one that gets incremented. Your glbfunc() does not see this variable and thus cannot print its value.
Try this:
if __name__ == '__main__':
global glbcnt
glbcnt = 0
...
Also, because of this, your entire glbcntmod.py file becomes pointless.
It's not because a variable is declared global once, that it becomes global everywhere.
"global glbcnt" simply means that from here on, in this scope, any references to glbcnt will refer to the global variable. No effects whatsoever are applied to other scopes, ie. other modules.

Related

Why one variable is accessed globally and other is not in Python?

I am trying to implement a simple BFS code.
Code:
def initalizeVertex():
n = int(input('Enter the no. of vertices.\n'))
for vertex in range(n):
Vertex.append(vertex)
node_adjacency[vertex] = []
def initalizeUndirectedEdges():
n = int(input("Enter the no. of edges.\n"))
print("Enter the space seperated edges.")
for i in range(n):
a,b = map(int,input().split())
node_adjacency[a].append(b)
node_adjacency[b].append(a)
def bfs():
current_level = 1
print(Vertex)
while(current_level_nodes):
for current_node in current_level_nodes:
for child_node in node_adjacency[current_node]:
if node_parent.get(child_node) == None:
node_parent[child_node] = current_node
next_level_nodes.append(child_node)
node_level[child_node] = current_level
current_level_nodes = [node for node in next_level_nodes]
next_level_nodes = []
current_level += 1
print(node_level)
print(node_parent)
def printData():
print(Vertex)
print(node_adjacency)
print(node_parent)
print(node_level)
print(current_level_nodes)
print(next_level_nodes)
if __name__ == "__main__":
root = 0
Vertex = []
node_adjacency = {}
node_parent = {root:None}
node_level = {root:0}
current_level_nodes = [root]
next_level_nodes = []
initalizeVertex()
initalizeUndirectedEdges()
printData()
bfs()
The codes output is :
This code gives me the error:
in bfs
while(current_level_nodes):
UnboundLocalError: local variable 'current_level_nodes' referenced before assignment
Clearly, the bfs() function cannot access the list current_level_nodes. I can solve this by passing the list current_level_nodes to the bfs function.
But, my question is why do I have to pass this list to bfs() function when I haven't passed the list Vertex to initalizeVertex() function and the function could still access and modify it?
Also I haven't passed any parameter to printData function but that function prints all the lists and dictionaries without giving any error.
Python will try to look for the variable at local scope 1st. If they're not found locally, Python will look for them globally.
for example -
In your printData() function -
Python will try to look for the variables locally, but no variables are defined in this method. So, Python will go at the global scope. It'll pick the values and will print them.
def printData():
print(Vertex)
print(node_adjacency)
print(node_parent)
print(node_level)
print(current_level_nodes)
print(next_level_nodes)
In another function bfs() -
Python will see current_level_nodes inside a while, and Python will try to find where the variable is defined. Here things will get tricky as you've assigned the same variable in the function later. This will confuse Python, and it'll throw the error.
line 1. - while(current_level_nodes):
line 2. - current_level_nodes = [node for node in next_level_nodes]
That's why you need to explicitly tell Python that you want to use global variable -
global current_level_nodes
The issue here involves the python compiler having compiled the rest of your function and it realizing that it must bind your variables within the function. This requires the global keyword as previously mentioned.
What is confusing here is that the error is shown on the first usage of the variable and not where the actual problem is. Here is an example:
access_only.py:
global_list = [1,2,3]
def f():
for x in global_list:
print(x)
f()
Here, we run it:
$python access_only.py
1
2
3
Now we change the function slightly to include an assignment to the list, as occurs in your code.
access_and_change.py:
global_list = [1,2,3]
def f():
for x in global_list:
global_list = [1, 2, 3]
print(x)
f()
Here we run it, but get an error on the for line even though the problem actually occurs on the global_list = line:
$python access_and_change.py
Traceback (most recent call last):
File "access_and_change.py", line 9, in <module>
f()
File "access_and_change.py", line 4, in f
for x in global_list:
UnboundLocalError: local variable 'global_list' referenced before assignment
The end result is the same, because you are assigning values to the lists, the global keyword must be used. If you eliminate the assignment within your function, the error goes away completely.
Thinking about this, I noticed that the error message says local variable referenced before assignment. I think the issue here is that because the function contains an assignment, the variable is considered to be local. Whereas if you just reference a global variable it is not considered a local variable. So, the assignment causes the variable to be considered local and the first time you reference it, python throws this error instead of searching the global/parent namespace because the compiler has already determined that it must be a local variable.
You have to define current_level_nodes is global in your bfs function this way :
def bfs():
current_level = 1
global current_level_nodes
...
Edit :
To access a global variable inside a function there is no need to use global keyword.
But if we need to assign a new value to a global variable or change it then we can do that by declaring the variable as global.
Because you used
next_level_nodes.append(child_node)
and
current_level_nodes = [node for node in next_level_nodes]
You need to use global;
If you didn't modify current_level_nodes in your function there was no need to use global

How to use values from variables imported from another file python

so I know this has been asked in several forms before, but I cannot relate to any of those, either I have something different or I just don't understand them.
The problem is I have script A and script B, and in script A I calculate and have all the variables I want to use in script B.
Script A has various functions, let's say for now I just want to pass a simple number from a variable in script A to script B , let's call the variable value .
I used from script_A import value .
Now, I have value initialized in script_A with 0 right at the top to say so, but script_A processes value, and gets a result clearly different from 0, but when I debug, I am getting in script_B value == 0, and not value == calculated_value_that_should_be_there.
I did not know what to do so I tough about scope,so I put it in the return of a function, I tried making variable value a Global variable. Nothing seems to work in the way that I am not passing the calculated 'value' but I am passing to script_B that 0 initialization.
P.S last thing I tried and what I saw from this topic is to import script_A as it was said with no namespaces. This has worked. When I write script_A.value it is calculated_value_that_should_be_there. But, I do not know why anything else that I described did not work.
script_A
from definitions import *
variable_1 = 0
variable_2 = 0
variable_3 = 0
variable_4 = 0
total = 0
respected = 0
time_diff = {}
seconds_all_writes = "write"
class Detect():
def __init__(self, data_manager, component_name, bus_name_list=None):
def __Function_A(self):
"""
global time_diff
global seconds_all_writes
process
script_B:
from script_A import respected
from script_A import total
import script_A
print aln_mon_detector.total
print aln_mon_detector.respected
I also want a dictionary
table_content.append(script_A.time_diff[file[script_A.seconds_all_writes])
I get
KeyError: 'writes'
this sounds a bit confusing without an example, but, in principle, what you're trying to do should work. Have a look at a minimum example below.
ModuleA - defining the variable
# create the variable
someVariable = 1.
# apply modifications to the variable when called
def someFunc(var):
return var + 2
# ask for changes
someVariable = someFunc(someVariable)
ModuleB - using the variable
import moduleA
# retrieve variable
var = moduleA.someVariable
print(var) # returns 3
This probably has to do with immutability. Depends on what value is. If value is a list (that is, a mutable object) and you append to it, the change should be visible. However, if you write
from module import x
x = 5
you are not changing the actual value, so other references to x will still show the original object.
If you have script A like this:
# imports
value = 0
... # some calculations
Re-organize script A as:
# imports
def main():
value = 0
... # some calculations
return value
Now you can import script A in script B and run calculations inside script B:
import script_A
value = script_A.main()
That is how you should organize code pieces in Python.

Python: Referencing global variables inside a function

I came across this problem of not being able reference golbal variables from inside of a function. It always throws an error saying "local variable 'variable_name ' referenced before assignment".
I wrote a simple code which will throw the same error in trying to return a array of product of two numbers.
table=[]
counter = 0
def multiplier(num):
if counter >9:
print (table)
else:
table.append(num*counter)
counter +=1
multiplier(num)
multiplier (5)
What am I doing wrong here? My original code requires the function to be called again and again for that I want to use a counter to keep track of how many times it is being called. This means I cannot initialize the counter inside of the function because once the function is called and because the counter is initialized inside the function, it will be reset.
Use global keyword at the first line in your function block.
Like:
def multiplier(num):
global counter
...
You have to declare
global counter
in your function to access the global variable instead of creating a local variable of the same name. The nicer solution would be to define a class, though.
Make counter a parameter of the function with a default value of zero. When you recurse, add one to the count.
table=[]
def multiplier(num, counter = 0):
if counter >9:
print (table)
else:
table.append(num*counter)
multiplier(num, counter+1)
multiplier(5)
Here is your function refactored to return a value instead of printing it.
table=[]
def multiplier(num, counter = 0):
if counter >9:
return table
else:
table.append(num*counter)
return multiplier(num, counter+1)
print(multiplier(5))
You can use global keyword to use the global variable. Following points to keep in mind:
Use global keyword only when you are changing the global variable value.
You can use global variable if only reading just by using the variable name (global variable definition not required here).
Example:
var = 10
def change_var():
global var
var = 2
return var
def read_var():
print "Variable is:",var
Hope this helps.

How to set a global variable

I tried to set a global variable in a funktion.
global the variable is set to Kategorie = ''
In one of my function I would like to set it to a other value:
elif methode=='show_select_dialog':
writeLog('Methode: show select dialog', level=xbmc.LOGDEBUG)
dialog = xbmcgui.Dialog()
cats = [__LS__(30120), __LS__(30121), __LS__(30122), __LS__(30123), __LS__(30116)]
ret = dialog.select(__LS__(30011), cats)
if ret == 6:
refreshWidget()
elif 0 <= ret <= 5:
writeLog('%s selected' % (cats[ret]), level=xbmc.LOGDEBUG)
global Kategorie
Kategorie = (cats[ret])
refreshWidget()
If I log the variable Kategorie in function refreshWidget the value is correct (cats[ret]), but after that if the function refreshedWidget is called again the value is gone...
elif methode == 'get_item_serienplaner':
sp_items = refreshWidget()
Once I have changed the variable to cats[ret] I would need it as cats[ret]
You have to declare your var outside your functions and everytime you want to use it inside a function you need to specify the global varName. As i see your global var name at declaration is Kategory and after you use Kategorie.
Python wants to make sure that you really know that you are using global variables by explicitly requiring the global keyword.
To use a global variable within a function you have to explicitly delcare you are using it.
Here a small example:
myGlobalVar= 0
def set_globvar():
global myGlobalVar # Needed to modify global copy of globvar
myGlobalVar = 5
def print_globvar():
print myGlobalVar # No need for global declaration to read value of myGlobalVar
set_globvar()
print_globvar() # Prints 5
in your case I see that you declare that you want to access global Kategorie but you do not declare access to global Kategory. I do not know if this is a simple typo or if they are 2 different variable. In any case you need to write global yourGlobalVariable
Are there really any globals in python? Yes there is a global keyword that allows you to access varibles in file scope. Another way of accessing the variable is to use the import statement. Lets say you have a file named file.py. In order to write to the variable you could. You could access another files variables just as easy.
import file
anyVariable = 42
# ...
def aFunc():
file.anyVarible = file.anyVarible + 1

Order of execution in Python methods [duplicate]

This question already has answers here:
Assigning to variable from parent function: "Local variable referenced before assignment" [duplicate]
(5 answers)
Closed 9 years ago.
I've tried looking at a few different examples, but I'm not really sure why this isn't working. Say I've some code like this:
def loadVariable():
global count
count = 0
def loadDictionary():
location = 'some location'
global myDict
myDict = pickle.load(open(location, 'rb'))
def main():
loadVariable()
loadDictionary()
for item in myDict:
if item.startswith("rt"):
count += 1
item = item[3:]
if __name__ == '__main__':
main()
To my eyes, the if statement is executed which starts the main() method. Then, the variable which is global is loaded, the dictionary is loaded and the for loop is executed.
However, when I run the code I am told that the local variable count is referenced before its assignment. Why is that happening?
Edit (Explaining some of the things I've written in comments):
This doesn't work (although I think that's because global is used wrong here):
global count
def loadVariables()
count = 0
def main():
loadVariables()
rest of code etc
This doesn't work either:
def loadVariables()
count = 0
def main():
global count
loadVariables()
rest of code etc
The only way thus far I've gotten it to work is using the link provided above, which is to treat the count as a list, like so:
def loadVariables():
global count
count = [0]
def main():
loadVariables():
rest of code etc
count[0] += 1
global means that within the function containing the global declaration, the name in the global declaration refers to a global variable. It does not mean "this thing is a global variable; treat it as global everywhere." In main, the names count and myDict refer to local variables, because main does not declare that it wants to use the globals.
The issue is that you're not declaring count as a global variable in the main function, so when the compiler sees that you're (eventually) assigning to it, it assumes that it's a local variable. Since it's value is read before it's assigned, you get an exception.
So, the most basic fix is just to add global count at the top of main(), but I think avoiding globals would be a better option. Why not have loadVariable and loadDictionary return their results, rather than assigning them to globals? If in main() you did count = loadVariable(), count would be a local variable, and you'd have no problems later trying to reassign it.
Here's a simple example of how global works
global_var = 0
def updater():
global global_var
global_var += 1
def stuff(x):
updater()
return global_var + x
if __name__ == '__main__':
stuff(2) # returns 3

Categories

Resources