SoFunction
Updated on 2024-10-29

Errors easily encountered when setting variables as default values in Python

Think about the code snippet below:
 

def foo(numbers=[]):
  (9)
  print numbers

Here, we define a list (empty by default), add 9 to it and print it out.
 

>>> foo()
[9]
>>> foo(numbers=[1,2])
[1, 2, 9]
>>> foo(numbers=[1,2,3])
[1, 2, 3, 9]

Doesn't that seem to work? But when we call the foo function without the number argument, something magical happens:
 

>>> foo() # first time, like before
[9]
>>> foo() # second time
[9, 9]
>>> foo() # third time...
[9, 9, 9]
>>> foo() # WHAT IS THIS BLACK MAGIC?!
[9, 9, 9, 9]

So, what's going on here? Intuition tells us that no matter how many times we call the foo function without the number argument, the 9 here should be assigned to an empty list. this is wrong! In Python, the default value of a function is instantiated when the function is defined, not when it's called.

So we still ask, why is this default value given a different value when the function is called? Because each time you assign a default value to a function, Python stores that value. If you override the default value when you call the function, then this stored value is not used. When you don't override the default value, then Python makes the default value refer to the stored value (numbers in this example). It does not copy the stored value to assign a value to this variable. This concept can be a bit overwhelming for beginners to understand, so it can be understood like this: there are two variables, one internal and one at the current runtime. The reality is that we have two variables to interact with the same value, so once the value of numbers changes, it also changes the record of the initial value stored inside Python.

Then the solution is as follows:
 

def foo(numbers=None):
  if numbers is None:
    numbers = []
  (9)
  print numbers

Usually, when people hear this, people ask another question about default values. Think about the following program:
 

def foo(count=0):
  count += 1
  print count

When we ran it, the results were exactly what we expected:
 

>>> foo()
1
>>> foo()
1
>>> foo(2)
3
>>> foo(3)
4
>>> foo()
1

What is the reason for this? The secret is not with the default value being assigned, but the default value itself. An integer is an immutable variable. Unlike a list, an integer variable cannot be changed during the execution of a function. When we execute the statement count+=1, we don't change the value of the count variable. Instead, we made count point to a different value. However, when we did (9), we changed the original list. This is the result.

Here's another example of the same problem you'll run into when using default values in functions:
 

def print_now(now=()):
  print now

As before, the value of () is variable, then it will only be computed at the time the function is defined, so it will return the same time no matter how many times it's called - the time output here is the time the program was interpreted and run by Python.

>>> print_now()
1373121487.91
>>> print_now()
1373121487.91
>>> print_now()
1373121487.91

* This problem and its solution are similar in Python and in Python, the only difference being that the print expression in Python is supposed to be a function call (print(numbers)).