I’m writing a small helper that collects validation messages. If I don’t pass in a list, I want each call to start with an empty one. Instead, messages from an earlier call appear in the next result.
def add_warning(message, warnings=[]):
# Append to the supplied list, or the default list if none was passed.
warnings.append(message)
return warnings
first = add_warning("Missing email")
print(first) # Prints ['Missing email'] at this point.
second = add_warning("Invalid postcode")
print(second) # Includes 'Missing email' from the previous call.
print(first is second) # True: both names refer to the same list.
I expected the second result to contain only "Invalid postcode". I’m also surprised that inspecting first after the second call shows both messages, even though I never explicitly updated first.
How are mutable default arguments in Python evaluated? Is the list created when the function is defined or each time it runs?
What is the usual way to make an omitted argument produce a fresh list while still allowing a caller to pass an existing list that the function should modify?