3

Been experiencing this weirdness in my program. Here is a snippet of the part that is giving trouble:

#!/usr/bin python
def test_func( newList, myList=[] ):
    for t in newList:
        for f in t:
            myList.append(f)
    return myList

print test_func([[3, 4, 5], [6, 7, 8]])
print test_func([[9, 10, 11], [12, 13, 14]])

The first time the function is called, it produces

[3, 4, 5, 6, 7, 8]

The second time

[3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]

I don't know why it does this. Are python functions static in that they retain the values passed to them in subsequent calls or am I missing something in my code?

smac89
  • 39,374
  • 15
  • 132
  • 179

3 Answers3

8

Although an answer has been accepted, it is interesting as well as important to understand why this happens, so as to avoid not-so-obvious pitfalls.

An excerpt from the Python documentation for compound statements :

Default parameter values are evaluated when the function definition is executed. This means that the expression is evaluated once, when the function is defined, and that the same “pre-computed” value is used for each call. This is especially important to understand when a default parameter is a mutable object, such as a list or a dictionary: if the function modifies the object (e.g. by appending an item to a list), the default value is in effect modified. This is generally not what was intended. A way around this is to use None as the default, and explicitly test for it in the body of the function

Please refer to the StackOverflow Discussion here for a discussion related to mutable arguments within the Python language. The discussion points to a very interesting and informative article on Effbot - Python Default Values which gives a good explanation of why this behavior is observed and the places where such a behavior is desirable - for e.g. a calculator function that performs very computing-intensive calculations may use a dictionary mutable as a default parameter to store the results of a calculation keyed by the parameters used for the calculation. In such a case, when the client requests for a calculation to be performed, the function can look up the dictionary mutable and return the values if already present, else perform the calculation.

Hopefully, this answer provides an insight into this "astonising" behavior of python and help in designing functions that work correctly and are performant.

The General
  • 1,239
  • 2
  • 17
  • 28
Prahalad Deshpande
  • 4,709
  • 1
  • 20
  • 22
7

Don't use mutable as keyword arguments.

def test_func( newList, myList=None ):
    myList = [] if myList is None else myList     
Cjkjvfnby
  • 134
  • 3
4

Python stores default values for optional arguments. If you modify their value, it will still be modified in the subsequent calls.

There's a good explanation on this thread: Python optional parameters

To make a work around in your case, create a new one instance of myList every time the function is called when myList not is specified.

Like this:

#!/usr/bin python
def test_func( newList, myList=None ):
    if myList is None:
        myList = []
    for t in newList:
        print "t:", t
        for f in t:
            myList.append(f)
    return myList

print test_func([[3, 4, 5], [6, 7, 8]])
print test_func([[9, 10, 11], [12, 13, 14]])
Community
  • 1
  • 1
davvs
  • 1,029
  • 1
  • 11
  • 18