Bitten by Python's Pass-By-Reference

I just got bitten by an interesting bug related to Python's pass-by-reference feature. I had a class method (mymethod) with a keyword argument (mykwarg) that defaulted to {}. I thought that each time mymethod was called, if mykwarg wasn't passed then it would default to an empty dict.

In reality, when the class was read by Python it evaluated the {} and made the default value a reference to the dict in memory. So each time mymethod was called without passing mykwarg, it was defaulting to that memory reference which contained data from a previous use. Here's an example class:

:::python
class MyClass(object):
    def my_method(self, my_kwarg={}):
        return my_kwarg    

And here's an iPython shell session illustrating what I mean:

In [2]: first_class = MyClass()

In [3]: kwarg = first_class.my_method()

In [4]: kwarg
Out[4]: {}

In [5]: kwarg.update({'foo': 'bar'})

In [6]: kwarg
Out[6]: {'foo': 'bar'}

In [7]: kwarg = first_class.my_method()

In [8]: kwarg
Out[8]: {'foo': 'bar'}

In [9]: second_class = MyClass()

In [10]: other_kwarg = second_class.my_method()

In [11]: other_kwarg
Out[11]: {'foo': 'bar'}

The fact that the kwarg wasn't defaulting to a fresh dict each time led to a lot of confusion before I realized what was happening! There are a couple of ways to solve the issue, but the easiest is probably this:

:::python
class MyClass(object):
    def my_method(self, my_kwarg=None):
        my_kwarg = my_kwarg or {}
        return my_kwarg