Function arguments in Python

Shaphil Mahmud
2 min readApr 25, 2020

Common pitfalls in Python functions

The Mysterious behavior of function arguments in Python.

You may have already seen some of the odd ways arguments in Python functions behave. Let’s look at those weird behaviors and try to explain them. All my examples are run on Python 3.8, but they are not specific to this version of Python and should run normally in other versions without any problems.

Not being able to change argument reference

Let’s demonstrate this with an example

a = 5

def change(x):
x = 10
print(x)

change(a) # expect a to be 10
print(a) # but a is still 5

The value of the passed-in argument does not change

What’s happening here is that a=5 creates a new int object of the value 5 and assigns it to the named reference a.

  • The call to change(a) makes x refer to a.
  • But within the function body the line x = 10 makes x point to a new int object of the value 10. At this point x has no idea what a is.
  • Thus the change function only changes references for its own parameter x and not of the value that was passed in.

This behavior occurs because variables in Python are really named references to objects and not the objects themselves. The box holding values does not work here.

If you really need to change the value of an immutable object just return the new value from the function. Like this,

# Returning values from function
def change(x):
x = 10
return x

Persisting values in default arguments

Here’s another example that you may already have seen before,

>>> def add_salt(food=[]):
... food.append('salt')
... print(food)
...
>>> salad = ['cucumber', 'tomatoes']
>>> add_salt(salad)
['cucumber', 'tomatoes', 'salt']

Everything’s fine, right? But see what happens when the add_salt function is called without any arguments.

>>> add_salt()  
['salt']
>>> add_salt()
['salt', 'salt']
>>> add_salt()
['salt', 'salt', 'salt']

This is because of how default arguments in Python functions are evaluated. They are evaluated only once when the interpreter first encounters them. When they are first encountered by the interpreter? When the interpreter first encounters the def statement, it binds the name add_salt to a function object and evaluates its parameters, here food=[]. When you call add_salt without any arguments for the first time, an empty list object is created and bound to the named reference food. Next time you call add_salt without any argument, 'salt' is added to that empty list that food refers to because it is not evaluated again.

This is a common problem in python and to avoid this, do not use any mutable object as the default argument of a function definition.

Originally published at https://blog.shaphil.me on April 25, 2020.

--

--

Shaphil Mahmud

Fullstack Software Engineer. Lover of the backend. Friends with the Frontend. https://shaphil.me