I have a nested function where I am trying to access variables assigned in the parent scope. From the first line of the next() function I can see that path, and nodes_done are assigned as expected. distance, current, and probability_left have no value and are causing a NameError to be thrown.
What am I doing wrong here? How can I access and modify the values of current, distance, and probability_left from the next() function?
def cheapest_path(self):
path = []
current = 0
distance = 0
nodes_done = [False for _ in range(len(self.graph.nodes))]
probability_left = sum(self.graph.probabilities)
def next(dest):
log('next: %s -> %s distance(%.2f), nodes_done(%s), probability_left(%.2f)' % (distance,self.graph.nodes[current],self.graph.nodes[dest],str(nodes_done),probability_left))
path.append((current, distance, nodes_done, probability_left))
probability_left -= self.graph.probabilities[current]
nodes_done[current] = True
distance = self.graph.shortest_path[current][dest]
current = dest
def back():
current,nodes_done,probability_left = path.pop()
The way Python’s nested scopes work, you can never assign to a variable in the parent scope, unless it’s global (via the
globalkeyword). This changes in Python 3 (with the addition ofnonlocal), but with 2.x you’re stuck.Instead, you have to sort of work around this by using a datatype which is stored by reference:
Note that this is why your list variables work – they’re stored by reference, and thus modifying the list modifies the original referenced list. If you tried to do something like
path = []inside your nested function, it wouldn’t work because that would be actually assigning topath(which Python would interpret as creating a new local variablepathinside the nested function that shadows the parent’spath).One option that is sometimes used is to just keep all of the things that you want to persist down into the nested scope in a
dict: