0

The below function retains the values in its list every time it is run. I recently learned about this issue as a Python 'gotcha' due to using a mutable default argument.

How do I fix it? Creating a global variable outside the function causes the same issue. Passing a list into the function breaks the recursion and only displays the first level of categories.

def build_category_list(categories, depth=0, items=[]):
    '''Builds category data for parent select field'''
    for category in categories:
        items.append((category.id, '-' * depth + ' ' + category.name))
        if category.children:
            build_category_list(category.children, depth + 1)
    return items
Casey
  • 2,611
  • 6
  • 34
  • 60
  • How does passing a list into the function "break the recursion"? Just make `items` a non-keyword parameter, add `item` to the recursive calls, and pass a new list when you call the function and it should work. – juanpa.arrivillaga Sep 30 '16 at 21:48

2 Answers2

2

There is no need to pass the list inside the recursive function, just concatenate the results of the subsequent calls to the current list:

def build_category_list(categories, depth=0):
    '''Builds category data for parent select field'''
    items = []
    for category in categories:
        items.append((category.id, '-' * depth + ' ' + category.name))
        if category.children:
            items += build_category_list(category.children, depth + 1)
    return items
Antoine
  • 3,880
  • 2
  • 26
  • 44
1

Passing the list in or by checking a null value would solve the issue. But you need to pass the list down the recursion:

def build_category_list(categories, depth=0, items=None):
    if not items:
        items = []
    '''Builds category data for parent select field'''
    for category in categories:
        items.append((category.id, '-' * depth + ' ' + category.name))
        if category.children:
            build_category_list(category.children, depth + 1, items)
                                                              ^^^^^
    return items

Alternatively, use the return value to construct the answer - my preference see Antoine's answer...

AChampion
  • 29,683
  • 4
  • 59
  • 75