0

I'm sorry if the title is misleading, but I could not put it in any other way.
I am trying to implement bfs and dfs in order to remember some concepts, but and odd behavior is going on with the recursive versions of the codes.

This is what is happening:

def rec_dfs(g, start_node, visited=[]):
    visited.append(start_node)
    for next_node in g[start_node]:
        if next_node not in visited:
            rec_dfs(g, next_node, visited)
    return visited

graph2={'A': ['B', 'C', 'D'],
       'B': ['A', 'E', 'F'],
       'C': ['A', 'F'],
       'D': ['A'],
       'E': ['B'],
       'F': ['B', 'C']}

rec_dfs(graph2, "A") #['A', 'B', 'E', 'F', 'C', 'D']               OK
rec_dfs(graph2, "A") #['A', 'B', 'E', 'F', 'C', 'D', 'A']          NOK
rec_dfs(graph2, "A") #['A', 'B', 'E', 'F', 'C', 'D', 'A', 'A']     NOK

It should always return the first case, but when I investigated I could see that the second call already had "visited" populated.

If I call the function like:

rec_dfs(graph2, "A", []) #['A', 'B', 'E', 'F', 'C', 'D']  OK
rec_dfs(graph2, "A", []) #['A', 'B', 'E', 'F', 'C', 'D']  OK
rec_dfs(graph2, "A", []) #['A', 'B', 'E', 'F', 'C', 'D']  OK

it works just fine...
I would really appreciate if someone could explain why this behavior is happening, and if there is a way to avoid it.

Thanks!

GuiFGDeo
  • 706
  • 1
  • 8
  • 29
  • Really weird, it looks like the visited array in the supposedly local kwargs dictionary is global for some reason. What version of python is it btw? – Greg K. Jan 07 '19 at 01:27
  • Ok, really interesting. Scratch that kwargs I was talking about. Turns out that mutable default arguments save state between calls and they are initialized only during the function definition. http://code.activestate.com/recipes/577786-smarter-default-arguments/. So making those 2 calls afterwards is no different than recursing a bit more using the same state. If you wanna reset the state you have to explicitly re-init the array. – Greg K. Jan 07 '19 at 01:32
  • Wow, never thought that python did that hahaha... But thanks a lot @GregK.. If you dont mind, answer the question and I can accept that as the answer :) BTW, Python 3.6.5 – GuiFGDeo Jan 07 '19 at 01:41

1 Answers1

1

You're using visited array as a mutable default argument which is essentially initialized to an empty array only once at definition according to http://code.activestate.com/recipes/577786-smarter-default-arguments/.

During each subsequent call to rec_dfs(), if visited array is not explicitly re-initialized, it will maintain its state during each subsequent function call.

Greg K.
  • 686
  • 1
  • 5
  • 18
  • Thanks! I wonder if there is any way to avoid this, making it so that the array is reinitialized on its own instead of explicitly passing it – GuiFGDeo Jan 07 '19 at 01:52
  • Not sure if there is any pythonic way to do something like that, but since it has this behavior I think this cannot be avoided. IMHO it still is really elegant and differentiates the dfs start calls from the recursive ones – Greg K. Jan 07 '19 at 02:02