How i ran into production issue with python default arguments?

How i ran into production issue with python default arguments?

Overview

Hello World! This was the first bug i have put into production environment after I started using Python. Like any other production issue, i have deployed the code changes i did on Friday afternoon and when i was planning to leave home in the evening, this bug started to show its ugly face. It's a bug due to using mutable default arguments into functions in Python. For a person who is a beginner in Python from Java world, this bug was quite confusing.

Issue

Let me put down the closer version of code which caused this issue.

def save_world(key, name, tools = {}):
    print('I am {}, fighting to save the world'.format(name))

    tools[key] = name
    # Other logic goes here
    return tools
mission1 = save_world('user1' , 'Nithila') 
# Output: I am Nithila, fighting to save the world
mission2 = save_world('user2' , 'Bowrna')
# Output: I am Bowrna, fighting to save the world

Expected behaviour i thought

I assumed that on each call to save_world function, the tools variable will be initialised with empty dictionary and filled with values. I expected the output to look like below:

print(mission1)
{'user1': 'Nithila'}
print(mission2)
{'user2':'Bowrna'}

Actual behaviour and the output is:

print(mission1) 
{'user1': 'Nithila'}
print(mission2)
{'user1': 'Nithila', 'user2': 'Bowrna'}
print(mission1) # Tried printing mission1 again and this is the result. Woah! both mission1 and mission2 #points to same result.
{'user1': 'Nithila', 'user2': 'Bowrna'}
print(id(mission1))
4582230208
print(id(mission2))
4582230208

Under the hood in Python, default mutable argument tools is initialised once and it's getting added/updated as we keep on invoking that function.

I used the response from this function and returned it to the end user via an API :( That's a security breach and added fuel into fire. PyCharm editor shows warning for default mutable argument which I didn't carefully read when in development phase. I learned this lesson hard way by putting this buggy code into production environment.

[Stackoverflow response which i found very useful] (stackoverflow.com/questions/1132941/least-a..)

Some important takeaways about Python from the stackoverflow responses are:

  1. Functions in Python are first-class objects.

  2. A function is an object being evaluated on its definition; default parameters are kind of "member data" and therefore their state may change from one call to the other - exactly as in any other object.

Hope you find this article useful. If there is any correction , please do share in comments. Thanks for reading :)