2

I'm writing a simple DFS algorithm, but when I run the function, it seems like the argument I'm passing in is carried on into the next call. I feel somewhat comfortable with how scoping in Python works, but I've never really considered how scoping works for arguments. Can someone explain how this scoping issue is occurring?

The only reason I can think of is that the default value I give path isn't created anew every time I run the function...?

Graph Object:

graph = {
        1: [2,8,12],
        2: [3,7],
        3: [4,5,6],
        8: [9],
        9: [10,11],
        12: [13],
        13: [14]
      }

DFS Algorithm:

def dfs_dict(graph, curr, val, path=[]):
  path.append(curr)
  print "Path: " + str(path)
  if curr == val:
    return path
  else:
    if curr in graph: # not a disconnected node/leaf
      for child in graph[curr]:
        if child not in path:
          tmp = dfs_dict(graph, child, val, path)
          if tmp:
            return tmp

How I'm running DFS:

if __name__ == '__main__':
    print dfs_dict(graph, 1, 13)
    print dfs_dict(graph, 1, 7)

OUTPUT:

Path: [1]
Path: [1, 2]
Path: [1, 2, 3]
Path: [1, 2, 3, 4]
Path: [1, 2, 3, 4, 5]
Path: [1, 2, 3, 4, 5, 6]
Path: [1, 2, 3, 4, 5, 6, 7]
Path: [1, 2, 3, 4, 5, 6, 7, 8]
Path: [1, 2, 3, 4, 5, 6, 7, 8, 9]
Path: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Path: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
Path: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
Path: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
Path: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1]
None

1 Answer 1

3

The issue is the default value of path here: def dfs_dict(graph, curr, val, path=[]):

The list is instanciated once, when the code is first read, and then the same instance is used over and over, as shown in this example:

>>> def foo(bar=[]):
...  bar.append(1)
...  print(bar)
... 
>>> foo()
[1]
>>> foo()
[1, 1]
>>> foo()
[1, 1, 1]
>>> bar
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'bar' is not defined

You should start your function like this instead:

def dfs_dict(graph, curr, val, path=None):
    if path is None:
        path = []

EDIT: Also, as lists are mutables, you probably should make a copy at the beginning of dfs_dict in order not to modify the one used the the “parent” stack frame when you append items.

Sign up to request clarification or add additional context in comments.

1 Comment

I had thought the argument was instantiated when the function was called, not when the code is first read. Thanks for the clarification.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.