JackSilver JackSilver - 2 months ago 5x
Python Question

Mutable default attribute reset - could someone please guide me through this logic?

In this entry in the functions section of the Python documentation, I was confused by the following example:

def append(elem, to=None):
if to is None:
to = []
return to

# Out: [5]
append(3) # A new list is created
# Out: [3]

The point here is supposed to be that you are resetting "to" to an empty list at the beginning of every function call to avoid the following:

# Out: [5]
append(3) # A new list is created
# Out: [5, 3]

But how can you check that "to" is None to set it to []? It seems to me that you are either pulling in the "to" defined in the definition, or you are pulling in the "to" modified by the last call. How does this work?

This shouldn't be marked as a duplicate. I am referencing a particular example from the Python documentation page, and I already understood the idea that mutable type default values persisted.

The misunderstanding was that they only persist when their default value is mutable, not their final value, which wasn't clear to me before. This question will probably help clarify for others as well.


When you define a function with a default argument, the function uses that default values for that argument if it is not supplied. So in the case of append(5), to is not specified, so the function assumes the value of to to be None - it's effectively the same as calling append(5, None).

So now, the function checks if to is None, which it is, so to gets reassigned to an empty list. 5 gets appended to the list, and the list is returned.

When you make the second call append(3), it is again as if you called append(3, None). Again, the if to is None evaluates to True, and to is reassigned to an empty list. Then, 3 is appended to that empty list, and the list is returned.

Since the default argument (in this case None) is immutable, the operations on to do not persist the end of the function call. The function has its own chunk of memory which gets cleared when the function returns.

However, if the default argument was mutable (like for instance []), that value is created when the function is defined (i.e. when python sees def func(arg1, arg2=[]), it creates an empty list in memory and uses that list every time this function is called). Thus, any changes made to that list will persist the end of the function, since that mutable default argument was created when the function was defined (before the function was ever called).