Python confusion - convention, name and value

I start and get confused when I learn 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 display as 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's happening?

+5
source share
4 answers

The fact that X and Y are references to the same np.array([1,0,0]) object np.array([1,0,0]) , this means that regardless of whether the call is made via X or Y , the result will be the same, but the change Linking 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. Thus, the memory looks like this:

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

Now, if you do X[0] = 2 , which basically is not suitable for:

 X.__setitem__(0,2) 

therefore you are calling a method on an object . So now the memory looks like this:

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

If you, however, write:

 X = 2*X 

evaluated first 2*X Now 2*X not suitable for:

 X.__rmul__(2) 

(Python first looks to see if 2 __mul__ for X , but since 2 will raise a NotImplementedException ), Python will revert to X.__rmul__ ). Now X.__rmul__ does not change X : it leaves X intact , but creates a new array and returns this. X catches this new array, which now refers to this array).

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

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

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

+5
source

think of it this way: the equal sign in python assigns links.

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

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

X = 2*X forces X to point to a new thing, but Y still points to the address of the original X, so Y does not change

this is not entirely true, but its close enough to understand the principle

+8
source

It is more a convention and names than a reference and meaning.

At appointment:

 Y = X 

Then the name Y refers to the object pointed to by the name X In a sense, the pointer X and Y points to the same object:

 X is Y # True 

is checks to see if the names point to the same object!


Then it becomes complicated: you perform some operations on arrays.

 X[0] = 2 

This is called an “item assignment” and causes

 X.__setitem__(0, 2) 

What __setitem__ should (convention) is to update some value in the X container. Therefore, X must still point to the same object.

However, X * 2 is "multiplication", and the convention says that this should create a new object (again convention, you can change this behavior by overwriting X.__mul__ ). Therefore when you do

 X = X * 2 

Now the name X refers to the new object created by X * 2 :

 X is Y # False 

Shared libraries usually follow these conventions, but it’s important to emphasize that you can reverse this!

+3
source

When you say X = np.array([1, 0, 0]) , you create an object that has some methods and some internal buffers that contain actual data and other information in it.

Executing Y = X sets Y to denote the same actual object. This is called name binding in Python. You linked the same object that was bound to X to the name Y

Executing X[0] = 2 calls the object __setitem__ method, which does some things for basic buffers. If the object changes in place. Now, when you print the values ​​of either X or Y , the numbers that go out of these object buffers are 2, 0, 0 .

Execution X = 2 * X translates to X.__rmul__(2) . This method does not change X in place. It creates and returns a new array object, each of whose elements twice corresponds to an X element. Then you bind the new object to the name X However, the name Y is still tied to the original array, because you did nothing to change it. As an aside, X.__rmul__ used because 2.__mul__(X) not working. Massive arrays naturally define multiplication to be commutative, so X.__mul__ and X.__rmul__ must be the same.

It is interesting to note that you can also make X *= 2 , which will propagate the changes to Y This is because the *= operator *= converted to the __imul__ method, which modifies the input.

+2
source

Source: https://habr.com/ru/post/1264539/


All Articles