-2

Tested on Python version 3.7.5

Consider the small running example

from collections import deque


class Tree:
    def __init__(self, ident=None, childs=[]):
        self.ident = ident
        self.childs = childs
        print(f'childs of {ident}: {childs}')

    def traverse_bfs_path(self):
        queue = deque([([], self)])
        while len(queue) > 0:
            path, node = queue.popleft()
            yield path, node
            queue += [(path+[i], n) for i, n in enumerate(node.childs)]


if __name__ == '__main__':
    tree = Tree('a')   # Works as expected
    depth = 1
    spread = 1

    for path, node in tree.traverse_bfs_path():
        if len(path) < depth:
            nc = len(node.childs)
            for _ in range(nc, spread):
                node.childs.append(Tree('-', [])) # without the second argument this will not run!

This prints to console:

childs of a: []
childs of -: []
childs of -: []

I am wondering - when you remove second argument in the last line [] Python does not the default value ([] as well) but seems to use the same array for childs as the previous instance of Tree.

Removing the second argument results in an infinity loop and prints the following to the console:

childs of a: []
childs of -: []
childs of -: [<main.Tree object at 0x7efbfe329590>]

Can someone explain this behavior?

martineau
  • 119,623
  • 25
  • 170
  • 301
Matthias
  • 1,055
  • 2
  • 14
  • 26
  • Mutable default arguments are a common gotcha - see https://docs.python-guide.org/writing/gotchas/#mutable-default-arguments. – brunns Dec 18 '19 at 12:40
  • Read the dupe. Use `def __init__(self, ident=None, childs=None): if not childs: childs = []` as workaround – Patrick Artner Dec 18 '19 at 12:40

1 Answers1

1

You have a list as the default value for childs, so you're experiencing the side effects of mutable default args.

Essentially, whats happening is Python evaluates the param the first time the function/method runs, and uses that for the subsequent runs

https://docs.python-guide.org/writing/gotchas/#mutable-default-arguments

Jason
  • 11,263
  • 21
  • 87
  • 181