Bug caused by using changeable value as the default in "python method overload"​

Summary

Using a mutable object like an empty list as a default argument in Python methods can cause subtle and hard-to-debug issues. This occurs because default arguments are evaluated only once when the function is defined, leading all instances that don't explicitly pass the argument to share the same mutable object. Consequently, modifications to this shared object by one instance will unexpectedly affect others, as demonstrated by objects sharing the same memory reference for their default parameters. To prevent this, developers should use `None` as the default value and then initialize the mutable object inside the method if the argument remains `None`.

In python we can set the passed in parameter's default value to make the function has the same running feature as the method overload in Java.

Define a function like this:

def testFunction(self, param1, param2=None, param3=None):

Normally we use "None" as the parameter's default value. We can also use str/bool as the default value, but is it OK we use empty list [] as its default value?

This is our test program:

""" A test program using empty list as the passed-in parameter's
    default value.
"""
class TestFunc(object):

    def __init__(self, id, parm = []):
        self.ObjId = id
        self.parm = parm
    
    def addNewParm(self, newParm):
        self.parm.append(newParm)

    def printAllParm(self):for item in self.parm:
            print(item)

obj_A = TestFunc('obj_a')
obj_A.addNewParm('A')
obj_A.addNewParm('B')
print(str(obj_A.ObjId)+':')
obj_A.printAllParm()

print('-------------------------')
obj_B = TestFunc('obj_b')
obj_B.addNewParm('C')
obj_B.addNewParm('D')
print(str(obj_B.ObjId)+':')
obj_B.printAllParm()
print ('================')
print ("obj_A parm reference id:" +str(id(obj_A.parm)))
print ("obj_B parm reference id:" +str(id(obj_B.parm)))

When we run it, the result shows:

The value we added in object A also appeared in the object B. And the object A's parm and object B's parm shared same memory id. When this happened, it is difficult for us to find the program's problem during debugging.

-------------------------------------------------------------------------

The reason caused this problem is the python's value assignment feature in memory management . In C++ if we do this:

a = 1; b = a; b =2;

In C, 2 memory location will be arranged for the two parameters and then the value will be put in to the memory like this:

But if we do the same thing in python, python will fill a memory position with value 1 then point a and b to that position. When we change b's value to 2. Value 2 will be fill in another memory position, then point b to that new memory address.

 

So if we use a changeable value such as empty list [] as the default value, the two objects' parameter will point to the same memory address which hold the [] at the init process. And that is the reason why we got the unexpected running result. 

Note: This post is authorized to republish here by Yuancheng Liu, Systems Software Engineer at ZycraftUSV.PTE.LTD. Original post is here.

PYTHON

  RELATED

  COMMENTS

0

No comment for this article.