Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python confusion -- convention, name and value

Tags:

python

I am a beginner and have a confusion when I am learning python. If I have the following python code:

import numpy as np
X = np.array([1,0,0])
Y = X
X[0] = 2
print Y

Y will be shown to be array([2, 0, 0])

However, if I do the following:

import numpy as np
X = np.array([1,0,0])
Y = X
X = 2*X
print Y

Y is still array([1,0,0])

What is going on?

like image 592
SunnyIsaLearner Avatar asked Feb 21 '17 20:02

SunnyIsaLearner


2 Answers

think of it this way: the equals sign in python assigns references.

Y = X makes Y point to the same address X points to

X[0] = 2 makes x[0] point to 2

X = 2*X makes X point to a new thing, but Y is still pointing to the address of the original X, so Y is unchanged

this isn't exactly true, but its close enough to understand the principle

like image 109
Nullman Avatar answered Nov 02 '22 01:11

Nullman


That's because X and Y are references to the same object np.array([1,0,0]) this means that regardless whether a call is done through X or Y, the result will be the same, but changing the reference of one, has no effect.

If you write:

X = np.array([1,0,0])
Y = X

basically what happens is that there are two local variables X and Y that refer to the same object. So the memory looks like:

     +--------+
Y -> |np.array| <- X
     +--------+
     |[1,0,0] |
     +--------+

Now if you do X[0] = 2 that is basically short for:

X.__setitem__(0,2)

so you call a method on the object. So now the memory looks like:

     +--------+
Y -> |np.array| <- X
     +--------+
     |[2,0,0] |
     +--------+

If you however write:

X = 2*X

first 2*X is evaluated. Now 2*X is short for:

X.__rmul__(2)

(Python first looks if 2 supports __mul__ for X, but since 2 will raise a NotImplementedException), Python will fallback to X.__rmul__). Now X.__rmul__ does not change X: it leaves X intact, but constructs a new array and returns that. X catches by that new array that now references to that array).

which creates an new array object: array([4, 0, 0]) and then X references to that new object. So now the memory looks like:

     +--------+         +--------+
Y -> |np.array|     X ->|np.array|
     +--------+         +--------+
     |[2,0,0] |         |[4,0,0] |
     +--------+         +--------+

But as you can see, Y still references to the old object.

like image 23
Willem Van Onsem Avatar answered Nov 02 '22 02:11

Willem Van Onsem