Home Blog Bitten by Python's Pass-By-Reference

Bitten by Python's Pass-By-Reference

Posted in Python on July 14, 2010 (view comments)

I just got bitten by an interesting bug related to Python's pass-by-reference feature. I had a class method (my_method) with a keyword argument (my_kwarg) that defaulted to {}. I thought that each time my_method was called, if my_kwarg 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 my_method was called without passing my_kwarg, it was defaulting to that memory reference which contained data from a previous use. Here's an example class:

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:

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

Comments

blog comments powered by Disqus

Brandon Konkle

I've been creating websites for over 10 years, and I've been using Django since early 2008. I focus on high quality, well-tested, maintainable code and reliable high-performance deployments. Web development is something that I am very excited about, and I love finding elegant and innovative ways to push web applications further.

Latest Comments

© 2011 Copyright Brandon Konkle. All Rights Reserved.