Tim Kennell Tim Kennell - 20 days ago 9
Python Question

Accessing parent function's variable in a child function called in the parent using python

In Python 3.4, I would like to call a child function, defined outside the parent function, that still has access to the parent function's scope (see example below). While I have named the functions parent and child in the example below for ease of viewing, the functions I am thinking of have very separate tasks and it makes more sense to define them separately. I am used to doing the following commonly in JavaScript:

def parent():
test = 0
child()

def child():
test += 1
print(test)


However, I simply get an error when executing the above code. I tried a second variation using the 'nonlocal' keyword that also failed:

def parent():
test = 0
child()

def child():
nonlocal test
test += 1
print(test)


The error message being 'no binding for nonlocal 'test' found'. Is this possible in python as it is in many other languages or is the only option the following (not preferred):

def parent():
test = 0

def child():
nonlocal test
test += 1
print(test)

child()


Edit: passing the parent's variable to the child function won't work in my use case as I need to modify the parent's variable.

Edit 2: The parent and child methods are already part of a class that doesn't really logically have an attribute of a counter. The counter is something internal to the two functions to keep track of node visits in a graph (see real example below):

class Graph():
def depthFirstSearch(self):
for vertex in self.adjacency_list:
vertex.status = "not visited"
vertex.previous = None

visit_count = 0
for vertex in self.adjacency_list:
if vertex.status == "not visited":
self.depthFirstSearchVisit(vertex)


def depthFirstSearchVisit(self, vertex):
nonlocal visit_count
visit_count += 1

vertex.distance = visit_count
vertex.status = "waiting"

for edge in vertex.edges:
if edge.status == "not visited":
edge.previous = vertex
self.depthFirstSearchVisit(edge)

vertex.status = "visited"
visit_count += 1
vertex.distance_finished = visit_count

Answer

In this case, you'd probably like to use a class. They are really easy to get your head around. Note the self variable that is passed, and take a look here for a quick explanation of scope in classes.

#!/usr/bin/env python3

class Family(object):

    def parent(self):
        self.test = 0
        self.child()

    def child(self):
        self.test += 1
        print(self.test)

if __name__ == "__main__":
    Family().parent()

So, to translate to your code:

#!/usr/bin/env python3

class Graph(object):
    def depthFirstSearch(self):
        for vertex in self.adjacency_list:
            vertex.status = "not visited"
            vertex.previous = None

        self.visit_count = 0
        for vertex in self.adjacency_list:
            if vertex.status == "not visited":
                self.depthFirstSearchVisit(vertex)

    def depthFirstSearchVisit(self, vertex):
        self.visit_count += 1

        vertex.distance = self.visit_count
        vertex.status = "waiting"

        for edge in vertex.edges:
            if edge.status == "not visited":
                edge.previous = vertex
                self.depthFirstSearchVisit(edge)

        vertex.status = "visited"
        self.visit_count += 1
        vertex.distance_finished = self.visit_count

class Edge(object):
    status = "not vistited"

class Vertex(object):
    def __init__(self):
        self.edges = [Edge(), Edge()]

if __name__ == "__main__":
    graph = Graph()
    graph.adjacency_list = [Vertex(), Vertex()]
    graph.depthFirstSearch()

Nothing fancy needed.