Possible Duplicate:
“Least Astonishment” in Python: The Mutable Default Argument
I’m seeing some strange behavior related to variable scope while trying to run some unit tests (python 2.7):
I have a module containing a class called ‘Dummy’ which has a single list as an instance variable. In my unit tests for this module, I have two separate test cases that each create their own separate Dummy instance. Nevertheless, the Dummy instance in the test that runs second seems to contain the list that was created in the first test. Here’s the code:
mymodule.py:
class Dummy(object):
def __init__(self, mylist=[]):
self.mylist = mylist
test_mymodule.py:
class TestDummy(unittest.TestCase):
def testDummy1(self):
d1 = Dummy() # d1.mylist is empty, []
d1.mylist.append(1) # mylist = [1]
self.assertEqual(d1.mylist, [1])
def testDummy2(self):
d2 = Dummy() # d2.mylist = [1] !
d2.mylist.append(2) # d2.mylist = [1,2]
self.assertEqual(d2.mylist, [2]) # FAILS
Additional details:
-
If I put a
print mylistas the first line in Dummy’s init method, sure enough, on the second test run, it prints [1] as if mylist=[1] was passed in as an argument -
If I explicitly specify
dd = Dummy(mylist=[]), then the problem disappears. It seems to have something to do with default argument values, but why in any case it should spill over into a different scope is unclear to me.
This has nothing to do with unit tests, but everything to do with how Python handles default arguments to functions. Function default arguments are evaluated once when the
defstatement is executed.That means you have created one list which is used a default argument to
__init__and that list will live as long as the function exists.It is easy to avoid by using
None(or another sentinel value) as the default: