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
Related
Class 'Test' contains function 'test_variables'.
Functions 'update_d' and 'update_a' are declared within 'test_variables()'.
Variable 'index' is initialized to 0 in 'test_variables'
List A [1,2] is initialized in 'test_variables'
'update_d' and 'update_a' updates 'index' and prints it.
I can access elements of list A without using the global attribute,
but to access 'index' I have declared'global index' within 'update_d' and 'update_a'.
Why can I not access the variable index without global but can access a list?
index=0
class Test():
def test_variables():
def update_d():
global index
index=index+1+A[0]
print(index)
def update_a():
global index
index=index+1+A[1]
print(index)
index=0
A=[1,2]
update_d()
update_a()
test_variables()
In Python, the global keyword is only needed when you are writing to a variable. Inside test_variable() you have defined a NEW variable named index, though it seems your intent was to write to the variable defined outside that scope.
When you read from a variable name, Python starts in the innermost scope and if the name isn't found, continues looking in the containing scopes.
When you write to a variable name, Python only looks locally and creates a new variable if one of that name isn't found. The global keyword tells Python that the local scope should reference that name globally on assignment.
For this reason, global variables work best as constants, and variables you need to change should probably be passed in to a function as a parameter and the new value returned.
The list A (in addition to update_a and update_b) is defined within Test, while index is not.
It's not correct way of using classes.
Code:
class Test:
A = (1, 2)
def __init__(self, index):
self.index = index
def update_d(self):
self.index += 1 + self.A[0]
print(self.index)
def update_a(self):
self.index += 1 + self.A[1]
print(self.index)
def test_variables(self):
self.update_d()
self.update_a()
idx = 0
tst = Test(idx)
tst.test_variables()
Provided code does same as yours but with correct usage of classes.
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.
This question is a result of a student of mine asking a question about the following code, and I'm honestly completely stumped. Any help would be appreciated.
When I run this code:
#test 2
a = 1
def func2(x):
x = x + a
return(x)
print(func2(3))
it works perfectly fine. It is able to take the globally-scoped variable a and use its value to perform the calculation and return the value 4.
However, if I change it to this:
# test 3
a = 1
def func3(x):
a = x + a
return(x)
print(func3(3))
I then get an error:
local variable 'a' referenced before assignment
Why do I get this error only when I want to update the value of a within the function to a new value based on its original value? What am I not understanding? I feel like this second piece of code should work fine.
Thanks in advance for any help and insight.
a = 1
def func3(x):
global a
a = x + a
return(x)
print(func3(3))
Now it should work.
When you put the statement a=x+a inside the function, it creates a new local variable a and tries to reference its value(which clearly hasnt been defined before). Thus you have to use global a before altering the value of a global variable so that it knows which value to refer to.
EDIT:
The execution of a function introduces a new symbol table used for the
local variables of the function. More precisely, all variable
assignments in a function store the value in the local symbol table;
whereas variable references first look in the local symbol table, then
in the local symbol tables of enclosing functions, then in the global
symbol table, and finally in the table of built-in names. Thus, global
variables cannot be directly assigned a value within a function
(unless named in a global statement), although they may be referenced.
def func3(x):
a = x + a
return(x)
On the right hand right side of a = x + a (So, x + a), 'x' is passed as variable, where 'a' is not passed as a variable thus an error.
Without using globals:
a = 1
def func3(x, a=2):
a = x + a
return(x)
func3(3)
Returns: 5
If this works
x=5
def main():
for globe in locals():
globals().update(locals()[globe])
print x
main()
then why doesn't this?
x=5
def main():
for globe in locals():
globals().update(locals()[globe])
x+=1
print x
main()
The error in the latter statement claims that x is referenced before assignment, however it works in the first example...
In python when you assign a variable the declaration happens automatically.
So when you assign a value to x inside the function, python think that is a new local variable, shadowing the global x.
if you want to assign a value to the global x you can do this:
x=5
def main():
global x
x += 1
print x
main()
You cannot assign a global variable in python without explicitly doing so. By writing x+=1 you are assigning a value to x and are implicitly declaring x as a local variable. But it is not defined and therefore you get an error.
The loop has no actual effect, as the locals dictionary is empty.
If you want to use global variables in Python (which you shouldn't, but that's another matter), you should use the global keyword.
suffixing 1 and 2 your two functions, you can find local names (syntax slightly different in python 2) :
In [7]: main1.__code__.co_varnames
Out[7]: ('globe',)
In [8]: main2.__code__.co_varnames
Out[8]: ('globe', 'x')
So x have different status. In the second case the local x mask the global one, so x=x+1 cause the error, because not yet defined.
From docs :
If a name is bound in a block, it is a local variable of that block, unless declared as nonlocal or global.(...).If a variable is used in a code block but not defined there, it is a free variable.
I would like to create temporary variables visible in a limited scope.
It seems likely to me that you can do this with a "with" statement, and I would think there is a construct that makes it easy to do, but I cannot seem to find it.
I would like something like the following (but it does not work this way of course):
pronunciation = "E_0 g z #_1 m p l"
# ...
with pronunciation.split() as phonemes:
if len(phonemes) > 2 or phonemes[0].startswith('E'):
condition = 1
elif len(phonemes) < 3 and phonemes[-1] == '9r':
condition = 2
So is there a simple way to make this work, using built-ins?
Thanks!
Python creates local variables with function scope (once a name is used it stays alive until the end of the function).
If you really want to limit scope then "del <var>" when you want it explicitly discarded, or create separate function to act as a container for a more limited scope.
You can create a method
def process_pronunciation(pronunciation):
phonemes = pronunciation.split()
if len(phonemes) > 2 or phonemes[0].startswith('E'):
condition = 1
elif len(phonemes) < 3 and phonemes[-1] == '9r':
condition = 2
return condition
When you call the method, the local variable phonemes won't be available in the global namespace.
pronunciation = "E_0 g z #_1 m p l"
condition = process_phonemes(pronunciation)
You could do it with with, but I don't think it's worth the trouble. Basically (in a python function) you have two scopes - global or local, that's it. If you want a symbol to have a lifespan shorter than the function you'll have to delete it afterwards using del. You could define your own context manager to make this happen:
class TempVar:
def __init__(self, loc, name, val):
self.loc = loc
self.name = name
self.val
def __enter__(self):
if self.name in self.loc:
self.old = self.loc[self.name]
self.loc[self.name] = self.val
def __exit__(self, *exc):
if hasattr(self, "old"):
self.loc[self.name] = self.old
else:
del self.loc[self.name]
then you can use it to get a temporary variable:
with TempVar(locals(), "tempVar", 42):
print(tempVar)
The working is that it modifies the dict containing local variables (which is supplied to the constructor via locals()) on entry and restoring it when leaving. Please note that this relies on that modifying the result returned by locals() actually modifies the local namespace - the specification does NOT guarantee this behaviour.
Another (and safer) alternative that was pointed out is that you could define a separate function which would have it's own scope. Remember it's perfectly legal to nest functions. For example:
def outer():
def inner(tempVar):
# here tempVar is in scope
print(tempVar)
inner(tempVar = 42)
# here tempVar is out of scope
with statement does not have its own scope , it uses the surrounding scope (like if the with statement is directly inside the script , and not within any function, it uses global namespace , if the with statement is used inside a function, it uses the function's namespace(scope)).
If you want the statements inside a with block to run in its own local scope, one possible way would be to move the logic to a function , that way the logic would be running in its own scope (and not the surrounding scope of with.
Example -
def function_for_with(f):
#Do something.
with pronunciation.split() as phonemes:
function_for_with(phonemes)
Please note, the above will not stop phonemes from being defined in the surrounding scope.
If you want that as well (move the phonemes into its own scope), you can move the complete with statement inside a function. Example -
def function_with(pronunciation):
with pronunciation.split() as phonemes:
#do stuff
pronunciation = "E_0 g z #_1 m p l"
function_with(pronunciation)
Expanding on #skyking's answer, here's an even more magical implementation of the same idea that reads almost exactly like you wrote. Introducing: the with var statement!1
class var:
def __init__(self, value):
import inspect
self.scope = inspect.currentframe().f_back.f_locals
self.old_vars = set(self.scope.keys())
self.value = value
def __enter__(self):
return self.value
def __exit__(self, type, value, traceback):
for name in set(self.scope.keys()) - self.old_vars:
del self.scope[name]
### Usage:
line = 'a b c'
with var (line.split()) as words:
# Prints "['a', 'b', 'c']"
print(words)
# Causes a NameError
print(words)
It does all the nasty extracting of local variables and names for you! How swell. If you space it quirkily like I did and hide the definition in a from boring_stuff import * statement, you can even pretend var is a keyword to all of your confused co-workers.
[1] If you actually use this, the ghost of a dead parrot will probably haunt you forever. The other answers provide much saner solutions; this one is more of a joke.