0

Why does bad_function, but not good_function, print a different value every time I run it?

def bad_function(x = np.zeros(1)): # first function
    print(x)
    x[0] = np.random.randn(1)

bad_function() # 0
bad_function() # not zero


def good_function(x = None): # second function
    if x is None:
        x = np.zeros(1)
    print(x)
    x[0] = np.random.randn(1)

good_function() # zero
good_function() # zero
paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
Sam Min
  • 77
  • 5
  • 2
    Congratulations, you've stumbled upon Python's most classic gotcha! Here's a [previous question](https://stackoverflow.com/questions/1132941/least-astonishment-and-the-mutable-default-argument) about the subject. And an [informative writeup](http://effbot.org/zone/default-values.htm). – CrazyChucky Nov 22 '20 at 22:46
  • Where did you get this from? Seems unlikely that someone would demonstrate this "gotcha" but not say anything about it. – superb rain Nov 22 '20 at 22:58
  • I edited to question to clarify that print/return problem. I have now also edited the title, which I originally missed. – paxdiablo Nov 22 '20 at 23:01

3 Answers3

4

Ask yourself when np.zeros(1) is called in both cases. Alternatively, run this code:

def printingFn():
    print("printingFn")
    return 42

def func1(x = printingFn()):
    print("func1")

def func2(x = None):
    if x is None: x = printingFn()
    print("func2")

func1()
func1()
func1()

print()

func2()
func2()
func2()

You'll see that only one call is made to printingFn in the func1 sequence, because the default argument is calculated when the function is defined, not every time it is called:

printingFn
func1
func1
func1

printingFn
func2
printingFn
func2
printingFn
func2

That's also true of the func2 sequence, in that the default argument of None is evaluated at function definition. However, the code that calls printingFn, since the argument is None, happens on each call.

What that means in your case is that the good_function variant of x is being created freshly every time the function is called. The bad_function variant is hanging around so maintains the changes made when you assign something to x[0].

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
3

That's because the default parameter values are evaluated when the function definition is executed and then this value is used in any future function calls.

irezwi
  • 789
  • 8
  • 14
1

As @CrazyChucky and @irezwi mentioned, it's because of the default parameters. I highly recommend you go through CrazyChucky's link (and subsequent link)

If you're still not clear go to a python visualizer

make sure you select python 3.6 with anaconda. you'll see in step 5 or 6 why this happens and you can keep this in mind for the future

Gorlomi
  • 515
  • 2
  • 11