DEV Community

Discussion on: Tell me a bug story

Collapse
 
kenbellows profile image
Ken Bellows • Edited

Several years ago, I was working on a python application. Tbh I don't remember much of anything about the actual program, but it's not important. I started seeing some weeeeiiirrdd behaviors in a particular function after the first time it was called. Let's pretend this was the function:

def add_score(obj={'type': 'default', 'score': 0}):
    obj['score'] += 10
    return obj

The code calling the function in question often called it without supplying an argument, and expected to get back the same result every time:

add_score() #=> {'type': 'default', 'score': 10}

But what was actually happening was much stranger:

agent_1 = add_score()
agent_1['type'] = 'red'

agent_2 = add_score()
agent_2['type'] = 'blue'

agent_3 = add_score()
agent_3['type'] = 'orange'

print(agent_1)
print(agent_2)
print(agent_3)

What would you expect to see? I expected this:

{'type': 'red', 'score': 10}
{'type': 'blue', 'score': 10}
{'type': 'orange', 'score': 10}

But what I actually got was this:

{'type': 'orange', 'score': 30}
{'type': 'orange', 'score': 30}
{'type': 'orange', 'score': 30}

⁉⁉😵⁉⁉

It took me SO LONG to understand the problem. The problem is that the default object in the function signature, the {'type': 'default', 'score': 0} object, is parsed and defined at function definition time, and it exists in the scope surrounding the function, when I thought it was defined each time you called the function, within the function scope. NOPE! 🤦‍♂️

So every time I called the function with no arguments, it was operating on and returning the same object! So all the agent_x variables in the code up there are referring to the same thing!!!

Oh my god the amount of time I wasted on this bug... but on the plus side, the very first article I wrote on dev.to was on this very bug (and how JavaScript's default parameters work the way I had expected Python's to work), so it sorta got me into tech blogging! Thanks bug!