0

I searched around and found this article which gives me a lead on why this is happening -- it seems I've just come across a more complex and subtle case of it. But it's those subtleties that have me bewildered and looking for a clearer explanation. (I doubt it matters, but just in case: I'm using Python 2.7.x on Windows 7.)

The starting point is this bit of code, which I distilled from a much larger and more complex app where I first encountered the problem.

class MyClass():
    def printStuff(self,myList=[1,2,3],myInt=4):
        print '--------------------------------'
        print 'myList at start: '+str(myList)
        print 'myInt  at start: '+str(myInt)
        doNotCare = myList.pop()
        myInt = myInt - 1
        print 'myList at end:   '+str(myList)
        print 'myInt  at end:   '+str(myInt)

testMC = MyClass()
testMC.printStuff()
testMC.printStuff()
testMC.printStuff()

...which generates the following output:

--------------------------------
myList at start: [1, 2, 3]
myInt  at start: 4
myList at end:   [1, 2]
myInt  at end:   3
--------------------------------
myList at start: [1, 2]
myInt  at start: 4
myList at end:   [1]
myInt  at end:   3
--------------------------------
myList at start: [1]
myInt  at start: 4
myList at end:   []
myInt  at end:   3

Now, based on the various write-ups on how defaulted parameters are handled in functions, it seems like myInt should exhibit the same behavior as myList, i.e. it should decrement to 3, 2, 1. But obviously it doesn't.

The puzzle gets more complex if I modify the doNotCare = myList.pop() line, instead using a slice to update the list:

class MyClass():
    def printStuff(self,myList=[1,2,3],myInt=4):
        print '--------------------------------'
        print 'myList at start: '+str(myList)
        print 'myInt  at start: '+str(myInt)
        myList = myList[:-1]
        myInt = myInt - 1
        print 'myList at end:   '+str(myList)
        print 'myInt  at end:   '+str(myInt)

testMC = MyClass()
testMC.printStuff()
testMC.printStuff()
testMC.printStuff()

...which somehow defeats that unexpected retained value, yielding the output:

--------------------------------
myList at start: [1, 2, 3]
myInt  at start: 4
myList at end:   [1, 2]
myInt  at end:   3
--------------------------------
myList at start: [1, 2, 3]
myInt  at start: 4
myList at end:   [1, 2]
myInt  at end:   3
--------------------------------
myList at start: [1, 2, 3]
myInt  at start: 4
myList at end:   [1, 2]
myInt  at end:   3

So I suppose the first question would be, is this in fact just a more complex and subtle case of the default-parameter behavior described in the reference? If it is, then why doesn't the behavior apply to myInt -- or even to myList, when I manipulate it with slicing instead of pop?

1

1 Answer 1

1

Unlike lists, numbers are immutable, so they can't be changed. References to them can be reassigned, but a 1 will always be a 1.

And splicing doesn't produce this behavior because it creates a copy of the original, whereas pop modifies the original list.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks, that makes sense of it. So tuples wouldn't be affected either -- only lists, dictionaries, etc.
@JDM Right. Anything immutable, tuples included, are "safe". You need to be careful with mutable objects though.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.