2

If I run this snippet of code, I expect to see [0] returned twice. Instead, I see [0,1].

def append(flist=[]):
    # append the length of a list to the list
    flist.append(len(flist))
    return flist

print(append())
print(append())

Why does this happen? Shouldn't the expression be reset because of the scope? How do I access flist if it exists outside the function?

This example comes from https://www.toptal.com/python#hiring-guide on question "Q: What will be printed out by the second append() statement below?". It does contain a brief explanation, but I don't understand how this is possible. Anything I can think of to analyze memory hasn't shown me the values, but I'm also not sure what the right tools are to figure this out. Looking at things like locals() or dir() doesn't seem to produce anything meaningful.

ADataGMan
  • 449
  • 1
  • 7
  • 23

1 Answers1

2

Editors like PyCharm will actually warn you, if you try this.

Pycharm says: "Default argument value is mutable."

That's the problem: the value you provide as the default (the empty list) is an actual list, and like any other list, you can change it and if multiple variables have that list as a value, those changes will show up for all of them.

So, to fix that code (and get the behaviour you want), you'd do this:

def append(flist=None):
    # initialise if needed
    if flist is None:
        flist = []
    # append the length of a list to the list
    flist.append(len(flist))
    return flist

print(append())
print(append())

This gives you the expected behaviour, because for both calls, no list is passed, so flist is None and it is assigned a new empty list on every pass, instead of getting passed the initial default list twice (empty on the first run, containing 0 on the second).

The scope of the append function does not persist, as suggested in the original question. Instead, the default value exists in the same scope as the function definition. So, in this case, in the global scope.

Whenever the function is called, this globally defined list is modified and this is why this value, that was expected to be scoped to the function, persists.

Grismar
  • 27,561
  • 4
  • 31
  • 54
  • Thanks Grismar! Can you expand on WHY it's happening though? I can't understand how the scope flist is in persists when it is inaccessible to anything but that method. – ADataGMan Sep 11 '19 at 01:26
  • 1
    I've added a few lines - does that serve to answer the 'why'? Feel free to ask for more, if you have specific issues with the explanation. – Grismar Sep 11 '19 at 01:47