-1

I would like to understand why I don't delete the array in spite of function call in case of Numpy?

In the case of the function call mul2 exactly what should happen happens. But if I try exactly the same with mul, I have a kind of reference to the original array.

How can I solve the problem? Do I have to "copy" the array first and then put it into the function? Or can I make a copy in the function and then delete it? What would be better here?

import numpy as np

def mul(h):
  #g = np.zeros([h.shape[0],h.shape[0]])
   g = h
   g[:,0] *= 5
   print(g)

def mul2(h):
  h *= h
  print(h)

a = np.array([[1,2,3,4], [2,3,4,5], [3,4,5,6]])

for i in range(2):
  mul(a)
for i in range(2):
  mul2(5)

The results are:

[[ 5  2  3  4]
[10  3  4  5]
[15  4  5  6]]

[[25  2  3  4]
[50  3  4  5]
[75  4  5  6]]

25
25

but from the behavier of mul2 i expect this as the solution:

[[ 5  2  3  4]
[10  3  4  5]
[15  4  5  6]]
[[ 5  2  3  4]
[10  3  4  5]
[15  4  5  6]]
Airfox
  • 51
  • 1
  • 5
  • `*=` modifies the values inplace - eg: it alters the array it operates on with the resultant values... `g = h` doesn't create a *copy* - it just binds the name `g` to the object that `h` is bound to... so you've just got two names for the same array... – Jon Clements Sep 19 '18 at 11:21
  • The thing is `numpy` arrays are passed by reference (sort of...), so the function will not create a local copy of the array. This has to be done manually, with the `.copy()` method. – norok2 Sep 19 '18 at 12:02
  • Jup, looks like what I also found out. np.copy is here the solution. I answerd the question myself with a explanation. – Airfox Sep 19 '18 at 20:41

2 Answers2

0

The problem is, trivially, the way you call mul2(). What you do is computing the following:

mul2(5)

Given your definition of mul2(), the effect of the line h *= h is to have h * 5 stored to h, and since h is 5, what you get is h = 5 * 5, and hence your 25 being printed.

What you probably want to do is something like:

def mul2(h, n=5):
    h *= n
    print(h)  # not sure you really want this inside your function besides for debugging purposes, and even then...

This you would call like:

mul2(h, 5)

and will result in something similar to mul(h).

If you want that your original input is not modified, you could do something like:

def mul3(h, n=5):
   g = h.copy()
   g *= n
   print(g)  # see above

or even better:

def mul3(h, n=5):
   return h * n

This will create a copy of the array in h with the included modification, which you can print() or do whatever you want with.

Note that it is not good practice to modify the input of a function. Of course there are use cases for that but I would advise you to document this very well.

norok2
  • 25,683
  • 4
  • 73
  • 99
0

Hello guys from the internet, thank you so much for your answers. So maybe something went lost during the translation, but I wanted to know why mul does what it does and the processing and workflow is different from mul2.

To the solution:

g = np.copy(h)

Numpy and Python behave differently here, because numpy only points to the array. I think this is one of the reasons why numpy is so fast. Be that as it may, you do an operation with the array, it is done at the place in the array and overwrites the array. As shown above, this can be bypassed with copy. (A new array will be created.) (I don't think that the explanation is quite correct, but I hope that the explanation is easy to understand for others.)

Airfox
  • 51
  • 1
  • 5
  • I do believe that the way your original question is formulated does not match the content of this answer, although this might be the piece of information you were missing. Perhaps you should consider updating your question, if this is what you were after. In fact, I am pretty sure that no matter how much `np.copy()` you will put in your definition of `mul2()`, if you call it the way you did, i.e. `mul2(5)` you will never get a result that is related to the content of a in your original question, as your expected output would suggest. – norok2 Sep 20 '18 at 15:01