2

I'm currently working with graph traversal. find_path with path incremented like path = path + [start] returns [30, 3, 5, 8], whereas find_path2 with path incremented like path +=[start] returns a list with every value find_path2 has already traversed, [30, 3, 4, 0, 1, 2, 5, 8].

I'm guessing += acts like the append method where as path = path + [start] does a reassignment?

Can someone explain the difference between path +=[start] and path = path + [start]

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

def find_path(graph, start, end, path=[]):
    path = path + [start]
    if start == end:
        return path
    if not start 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

graph = {
    0: [],
    1: [],
    2: [],
    3: [4,2,5],
    4: [0,1],
    5:[8],
    10:[5,6],
    6:[],
    30:[3]
}
print find_path(graph,30,8) #[30, 3, 5, 8]
print find_path2(graph,30,8) #[30, 3, 4, 0, 1, 2, 5, 8]
Padraic Cunningham
  • 176,452
  • 29
  • 245
  • 321
starl
  • 23
  • 3

2 Answers2

4

One creates a new list (+), the other modifies the original list (+=):

In [28]: path = [30, 3, 4, 0, 1, 2, 5, 8]

In [29]: id(path)
Out[29]: 140580805174120

In [30]:  path = path + [7] # assignment = new list

In [31]: id(path)
Out[31]: 140580805174840 

In [32]: path = [30, 3, 4, 0, 1, 2, 5, 8]

In [33]: id(path)
Out[33]: 140580805175416

In [34]:  path += [7] # same as list.extend, modifies list

In [35]: id(path)
Out[35]: 140580805175416 

Also your mutable default arg will cause you trouble if you called the function twice you should use None as the arg value and set it to an empty list when you first call the function, not calling recursively:

def find_path2(graph, start, end, path=None):
    if path is None:
        path = []

That is actually somewhat the same as the difference between += and list = list + [value], the same object/list is used for repeated calls if you don't create a new object each time you call the function.

Community
  • 1
  • 1
Padraic Cunningham
  • 176,452
  • 29
  • 245
  • 321
  • Also, if OP (@starl) is interested in comparing `append()` and `+=`, here: http://stackoverflow.com/questions/2022031/python-append-vs-operator-on-lists-why-do-these-give-different-results – Tacocat Mar 31 '16 at 00:24
1
  1. path = path + [start] creates a new list. Existing references to the list are not updated, whereas += modifies the list in-place.
  2. Python has __iadd__so += is more than just syntactic sugar.
Mark Nunberg
  • 3,551
  • 15
  • 18