2

I came across something today that I considered very odd.

>>> import StringIO
>>> def test(thing=StringIO.StringIO()):
...   thing.write("test")
...   print thing.getvalue()
... 
>>> test()
test
>>> test()
testtest
>>> test()
testtesttest
>>> test()
testtesttesttest
>>> test()
testtesttesttesttest

Before today I would have read the line

def test(thing=StringIO.StringIO()):

as:

Declare a function which, whose kwargs dictionary, when called has a new StringIO by default as the value for the key 'thing', and add it to the current scope.

but from the example I think it's more like:

Declare a function. Construct a dictionary with a new StringIO in it. Assign this to the default kwargs of the function and add the function to the current scope.

Is this the correct interpretation? Are there any other gotchas to be aware of for default kwargs?

Joe
  • 46,419
  • 33
  • 155
  • 245

2 Answers2

4

Your second definition is perfectly correct. This behavior will happen with any mutable object. The common idiom is to use None as a guard.

def test(thing=None):
    if thing is None:
        thing = StringIO.StringIO()
    thing.write("test")
    print thing.getvalue()

See this answer on Python 2.x gotcha's and landmines for more detail.

Community
  • 1
  • 1
Daenyth
  • 35,856
  • 13
  • 85
  • 124
  • Yes that's exactly what I did. Just thought I'd check that I was doing it for the right reason. – Joe Apr 21 '11 at 15:23
2

Yes, the second interpretation is correct. It's one of the gotchas in Python. It's has been discussed here numerous times. See for example: "Least Astonishment" and the Mutable Default Argument

Community
  • 1
  • 1
vartec
  • 131,205
  • 36
  • 218
  • 244