>>> a = np.arange(9).reshape((3, 3))
>>> a
array([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])
>>> def sub(a):
... return a[:2, :2]
...
>>> sub(a)
array([[0, 1],
[3, 4]])
>>> sub(a) = np.arange(4).reshape((2, 2))
File "<stdin>", line 1
SyntaxError: cant assign to function call
>>> t = a[:2, :2]
>>> t = np.arange(4).reshape((2, 2))
>>> a
array([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])
>>> a[:2, :2] = np.arange(4).reshape((2, 2))
>>> a
array([[0, 1, 2],
[2, 3, 5],
[6, 7, 8]])
And that's pretty obvious why it happens like this: when I type t = ..
, I just 'relink' t
to other data in memory. But the questions are:
- how I can ... pass reference to the submatrix out of function?
Simply put, you cannot return an l-value from a function call in Python like you can in C++. In your case, Python assumes that you are assigning a value directly to the sub(a)
, which is a function call, and not to the object returned by it.
Offcourse, you can use Indexing to get the reference to the original object as described later. That will allow you to change the part of the original matrix.
- and still be able to change this submatrixes values?
You can change the values of the submatrix of an array inside the function itself, like so:
def sub(a):
a[:2, :2] = np.arange(4).reshape((2,2))
return a[:2, :2]
This will not only return
the modified submatrix, but it will also change the array itself.
Objects are Pass-by-Reference but their References are Pass-by-Value:
Just like Java, Python is pass-by-value, so all objects are passed as references into the function, and these references are passed by value.
So when you index this array object and modify its value inside the function, you are modifying the value of the location in memory that this reference points to, but if you change the reference itself then it won't modify the original object because its reference was only passed by value.
Use Indexing to Pass the Reference to an Object by Value:
Following this explanation, you can even go further and return the object's reference from the function by value and modify the matrix using it outside the function:
sub(a)
, which will return the reference by value to the submatrix, which is itself the reference to the original matrix passed by value.x = sub(a)
x[:] = np.ones((2,2))
This will also modify the original matrix a
because you have modified the value of the location in memory to which x
is referring.
>>> x = sub(a)
>>> x[:] = np.ones((2,2))
>>> x
array([[1, 1],
[1, 1]])
>>> a
array([[1, 1, 2],
[1, 1, 5],
[6, 7, 8]])
OR, as a shortcut:
>>> sub(a)[:] = np.ones((2,2))
>>> a
array([[1, 1, 2],
[1, 1, 5],
[6, 7, 8]])
Changing the Reference doesn't change the Object:
However, now if you set variable x
to np.ones((2,2))
then a
would not change, because by doing so, you are changing the reference itself which was passed by value.
>>> x = 2 # this won't change a because x is a reference passed by value
>>> a
array([[1, 1, 2],
[1, 1, 5],
[6, 7, 8]])
The correct action in Python
is:
In [97]: t=sub(a)
In [98]: t
Out[98]:
array([[0, 1],
[3, 4]])
In [100]: t[:]=np.arange(4).reshape(2,2)
In [101]: t
Out[101]:
array([[0, 1],
[2, 3]])
In [102]: a
Out[102]:
array([[0, 1, 2],
[2, 3, 5],
[6, 7, 8]])
The function returns a view
of the original array, the same as doing t = a[:2, :2]
outside the function. t=...
reassigns the variable, but t[:]=...
modifies the contents (array elements) of the view. And since it is a view, the original array contents also change. This is same as your a[:2, :2] =...
.
As long as you use the [:]
, you don't need the intermediate variable assignment:
In [104]: sub(a)[:]=np.zeros((2,2))
In [105]: a
Out[105]:
array([[0, 0, 2],
[0, 0, 5],
[6, 7, 8]])
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With