W3_A1_Update_parameters_Test fails

Given that the Discourse search engine seems to work pretty well and people can find this thread, maybe it’s worth adding some more material about other “nasty surprises” you can get from the way object references work in python. Here’s another one that comes to mind:

Let’s suppose I have a numpy array called A:

A = np.random.randint(0, 10, (3,4))
print(f"A =\n{A}")
A =
[[6 3 7 4]
 [6 9 2 6]
 [7 4 3 7]]

Now suppose I make a “copy” of it and execute the following statements:

B = A
B[1,3] = 42
print(f"B =\n{B}")
B = 
[[ 6  3  7  4]
 [ 6  9  2 42]
 [ 7  4  3  7]]

But now watch this:

print(f"A =\n{A}")
A = 
[[ 6  3  7  4]
 [ 6  9  2 42]
 [ 7  4  3  7]]

Eeeek! What just happened? Because numpy arrays are python “objects”, when you make an assignment statement B = A, you are not actually creating a new copy of the memory object referenced by A. A python “object” variable is really what you would call a “pointer” in c or C++: it is just a “name” that points to the actual object in memory. So what B = A does is just create another variable that is an object reference to the same object in memory. That’s why modifying the contents of B also modifies the content of A. I’m sure I don’t need to emphasize that this can lead to very surprising side effects (surprising in a bad way). If your purpose is to make B an independent copy of the contents of A that you can modify without affecting A, the easiest way to do that is to use the “copy()” method as I showed in my earlier post on this thread:

B = A.copy()

Other equivalent ways to write that are:

B = np.array(A, copy = True)
B = np.copy(A)

It’s a matter of taste, but the first implementation seems simpler and cleaner.

Depending on how complex an object A is (e.g. if it also contains elements which are themselves object references), you might even need to do a “deep” copy:

B = copy.deepcopy(A)

Note that you need to import the copy package first in order to use deepcopy. The deepcopy is a bit more expensive, but is equivalent to “copy()” in the case the object in question is a “simple” object (with elements which don’t contain any object references). An example in which you need the “deep” version of copy is when the object in question is a python dictionary with elements that are objects (e.g. numpy arrays). Just doing “copy()” in that case doesn’t help: the deepcopy is required. Or you can do “copy” on each individual element, but that’s more code.

For more information on this, please see the numpy documentation (google “numpy copy”).