3
def f(x, arr=[]):
    arr.append(x)
    return arr
print(f(1),f(2))

o/p: [1,2] [1,2]

def f(x, arr=[]):
    arr.append(x)
    return arr
print(f(1))
print(f(2))

o/p: [1]
     [1,2]

Why does calling function f() in different ways change the output values? I have written the second function only for the sake of comparison with the first one. Sorry if that created confusion.

khelwood
  • 55,782
  • 14
  • 81
  • 108
  • Actually does the dupe adequately explain the 1st example? The 2nd example is exactly what the dupe is about and the classic example, the 1st one is perhaps worth another answer, should it be re-opened? – Chris_Rands Aug 08 '18 at 11:31
  • 3
    That's one part of the answer. The other is the fact that Python needs to evaluate all function parameters before a function can be called. So the order of execution in top example is `f(1); f(2); print(arr, arr)`, while in the second `f(1); print(arr); f(2); print(arr)`. – Amadan Aug 08 '18 at 11:34
  • I think this is a different question. The dupe explains the second example, but I think the interesting question here is why the first example is different. – mkrieger1 Aug 08 '18 at 11:34
  • Ok i've re-opened, please be aware the original dupe target explains the 2nd case https://stackoverflow.com/questions/1132941/least-astonishment-and-the-mutable-default-argument @Amadan you could write that as an answer – Chris_Rands Aug 08 '18 at 11:35
  • Possible duplicate of ["Least Astonishment" and the Mutable Default Argument](https://stackoverflow.com/questions/1132941/least-astonishment-and-the-mutable-default-argument) – Olivier Melançon Aug 08 '18 at 11:38
  • 1
    @OlivierMelançon: This is the very non-dupe that it was just reopened from, if you take a look at the comments :) – Amadan Aug 08 '18 at 11:40

1 Answers1

6

This is an interaction between two different things:

1) Function argument defaults in Python are not recalculated at each invocation, but at function definition time (bigger discussion at "Least Astonishment" and the Mutable Default Argument)

2) Python needs to evaluate all arguments to a function before it will call the function (e.g. to perform print(1+2, 5*3), 1+2 and 5*3 will need to be calculated before print is even considered)

Thus, if you call f multiple times without a second argument, it will just append to the same array you declared originally in the def. This is what you can clearly see in the second example. The first invocation prints arr after the first mutation ([1]); the second prints arr after the second one ([1, 2]).

The first example is different because of the second principle I stated: all the parameters are evaluated before the function is called. So print(f(1), f(2)) will first invoke f(1), changing arr to [1]; then f(2) will be evaluated, changing arr to [1, 2]. Since both function calls returned the reference to arr, print will then print the content of arr twice: [1, 2], [1, 2].

Amadan
  • 191,408
  • 23
  • 240
  • 301