简体   繁体   中英

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM