Why does my Python default argument keep its old value?

Short answer

Default arguments are evaluated once, when the function is defined — not on each call. A mutable default like [] is therefore shared by every call. Use None and create the list inside.

Here is the bug:

python
def add_lesson(name, lessons=[]):
    lessons.append(name)
    return lessons

add_lesson("Intro")     # ['Intro']
add_lesson("Basics")    # ['Intro', 'Basics']   <-- not what you wanted

That single list was created once, when def ran. Every call without an explicit argument gets the same list object, complete with everything previous calls put in it.

#The fix

python
def add_lesson(name, lessons=None):
    if lessons is None:
        lessons = []
    lessons.append(name)
    return lessons

Now each call that omits the argument gets a fresh list.

#The rule

Never use a mutable object as a default argument. That means [], {}, set(), and any class instance. Immutable defaults — numbers, strings, tuples, None, True — are all fine, because there is nothing to accumulate.

#Why Python works this way

Evaluating defaults once is what allows this to be fast and predictable:

python
def search(pattern, flags=re.IGNORECASE):

The alternative — re-evaluating on every call — would make every default a hidden function call. The trade-off is this one sharp edge, which is why every Python linter warns about it.