I recently posted on some Python Traps, focussing on code where changes in the values of sub-routine arguments were not reflected in the calling routines. The reverse can also be a problem: if an array, a, is passed to a sub-routine in VBA, then a new array, b, with the same values created in the sub-routine using b = a, any changes to b will not be reflected in a.
In Python things work differently; the statement b = a means that the array a is now also called b, so changes to b will also change a, both in the sub-routine and in the calling routine. This was discussed in some detail in The meaning of = in Python; this post looks at some practical examples, and how to create a new copy of an array, rather than just giving the existing array a new name.
The screenshots below illustrate further variations of the routines discussed in the Python Traps post:
- An array, x, is read from the spreadsheet and passed to a subroutine, either as a list, a list of lists, or a 1D or 2D Numpy array.
- In the subroutine an array, y, is created, either with the statement y = x, or with the Python copy or deepcopy commands.
- y is multiplied by a constant.
- y is retuned to the calling routine, as the function return value.
- y and x are returned to the spreadsheet.
In the first three examples below the array x is passed as a Python list or a 1D Numpy array. When the array y is created with y = x, the changes to y are also seen in x, but when x is created with y = np.copy(x), x is not affected by the changes to y. The Python copy function (y = copy.copy(x)) works the same way for a 1D list.
With a 2D list (list of lists) however the y array created with the Python copy function behaves the same as using y = x; the changes in y are also seen in x. This is because copy only creates a new object for the top level list. The lower level lists still refer to the same objects as in the x list. To create a new list of lists at all levels it is necessary to use the Python deepcopy function: y = copy-deepcopy(x).
The numpy copy command however works the same on all levels of Numpy arrays. In the final example below the 2D array x is not affected by the changes to y, which was created with y = np.copy(x).