2

EXAMPLE FUNCTION:

 def extendList(val, list=[]):
     list.append(val)
     return list

 list1 = extendList(10)
 list2 = extendList(123,[])
 list3 = extendList('a')

 print "list1 = %s" % list1
 print "list2 = %s" % list2
 print "list3 = %s" % list3

I've been reviewing some python interview questions and it seems I'm missing out on something basic here. For the script/function above I would have originally expected to see the following output for the reasons stated in the comment:

 list1 = [10] #because default is currently []
 list2 = [123, []] #because not using function default of list
 list3=[10, 'a'] #because function default list has had 10 appended

Instead, though, the result for for list1 is:

 list1 = [10, 'a'] #I don't understand.

It seems I'm missing out on what happens to a variable when it's passed back from a function in memory, possibly? It seems as though list1 when passed back from the function is pointing the variable at the default function 'list' parameter in memory. Then, this default function 'list' parameter is altered with the calling of list3. Finally, when printing list1 and list3 values, they're pointing at the same variable in memory and thus print the same result? Am I way off here?

Think I answered my own question here...

When checking out the memory address of the variables I received the following:

 print(hex(id(list1))) = 
 0x10b49a518

 print(hex(id(list2))) = 
 0x10b49a758

 print(hex(id(list3))) = 
 0x10b49a518

Could someone make sure I'm interpreting this correctly? Also, I'll leave this question open for anyone else that finds it via my horribly worded title XD

user2208604
  • 301
  • 2
  • 6
  • 15
  • 1
    Note that you don't `print` anything until **after** all three calls - rearrange a bit and you'll see the behaviour you expected. – jonrsharpe Oct 13 '14 at 14:56
  • http://stackoverflow.com/questions/1132941/least-astonishment-in-python-the-mutable-default-argument?lq=1? – g.d.d.c Oct 13 '14 at 14:58
  • @jonrsharpe Thanks for the comment. I had known how to get the output I wanted, but was confused why this wasn't resulting in that output as well. I've edited my post to show where the variables are at in memory and I thin this helps get to a good final answer. Thanks! – user2208604 Oct 13 '14 at 15:04

3 Answers3

3

Think of the default value for list as being created when the function is defined as opposed to with each call. Thus, the same list is passed back from the first and 3rd calls, so the same (final) value gets printed when all is printed at the end. As @johnsharpe pointed out, you'll see your expected behavior if you print the values in between calls.

Scott Hunter
  • 48,888
  • 12
  • 60
  • 101
  • I had played around with printing in between calls and saw that the output was as expected, but was confused when it printed all at once at the end. Thanks for the answer! I've gone ahead and edited my post to reflect the locations in memory of the variables – user2208604 Oct 13 '14 at 15:03
  • A follow up: the default value for list is created when the function is defined. But, that concept doesn't hold true for required parameters as well, right? For example, val isn't created when the function is defined as well, is it? – user2208604 Oct 13 '14 at 15:06
  • @user2208604: The value for `val` is coming from the caller, so there is nothing to be *created* here. – Scott Hunter Oct 13 '14 at 18:31
0

this will clear the output of list1 and list2

    list1 = extendList(10)
    print  list1
    list2 = extendList(123,[])

    list3 = extendList('a')
    print  list3 

while in case of list2 you are passing a different list object to list variable.

Vishnu Upadhyay
  • 5,043
  • 1
  • 13
  • 24
0

This is a classical experiment.

Here is how you could see things more clearly, I thought the above answers did not point out exactly what is going on.

Replace your function by

def extendList(val, list=[]):
    list.append(val)
    print inspect.getargspec(extendList).defaults[0] #This prints the default value of list
    return list

and then let's have a look at

list1 = extendList(10)     #Prints [10]
list2 = extendList(123,[]) #Prints [10]
list3 = extendList('a')    #Prints [10, 'a']

What it tells you is that when you have a mutable default argument, you can actually change it during a function call.

Flavian Hautbois
  • 2,940
  • 6
  • 28
  • 45