0

In the function below, when I use path = path + [start] then I will get the result ['A', 'B', 'E'] but when I use path += [start] then I will get the result ['A', 'B', 'D', 'E']. Why?

My code:

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

def find_path(graph,start,end,path=[]):

    path = path + [start]

    if start == end:
        return path
    if start not in graph:
        return None

    for node in graph[start]:
        if node not in path:
            newpath = find_path(graph,node,end,path)
            if newpath:
                return newpath 
    return None

print(find_path(graph1,'A','E'))
trotta
  • 1,232
  • 1
  • 16
  • 23
Newbie
  • 3
  • 1
  • `paht + [start]` creates a new list, while `+= [start]` does not. See [“Least Astonishment” and the Mutable Default Argument](https://stackoverflow.com/questions/1132941/least-astonishment-and-the-mutable-default-argument) to see why that is affecting your results. – Patrick Haugh Mar 12 '19 at 13:58
  • Ok, thanks, i will look over there ^^ – Newbie Mar 12 '19 at 15:14

3 Answers3

3

There are two things going on here:

First, the path=[] in your definition of find_path is a mutable default argument, which has a very surprising behavior if you're not expecting it. The short version is that the default value of path is not a new [] each time, but rather the same [] every time.

Second, path = path + [start] rebinds the name path to a new list object created by the concatenation, while path += [start] mutates the existing list object pointed to by path. The best resource I can think of for learning more about this distinction is the article Facts and myths about Python names and values.

The combination of the two means that you are mutating the same list each time; if you change either of them you will get separate list objects and not see this problem.

Daniel Pryden
  • 59,486
  • 16
  • 97
  • 135
0

The problem comes from usage of a mutable value as default argument in your find_path definition.

  • When you use path += [start] you actually alter the default value of path
  • When you use path = path + [start] you actually store the path argument in a local path variable before altering it.

more detail here

Tryph
  • 5,946
  • 28
  • 49
0

Sadly, for lists Python overloads += to mean the same as list.extend (in all cases rather than just when the difference is invisible), so it's going to extend the LHS with the RHS in-place, whereas the normal binary + will create a brand new list object, copy the LHS in it, then copy the RHS in it.

This is noticeable here because in Python default values are created during module parsing and bound to the function itself, you don't get a new value every time the function is invoked. So if you modify path in-place (which is what += does) it remains between invocations of the function.

Masklinn
  • 34,759
  • 3
  • 38
  • 57