Python混淆 - 约定,名称和值

Sun*_*ner 5 python

我是初学者,在学习python时会感到困惑.如果我有以下python代码:

import numpy as np
X = np.array([1,0,0])
Y = X
X[0] = 2
print Y
Run Code Online (Sandbox Code Playgroud)

Y将被证明是 array([2, 0, 0])

但是,如果我执行以下操作:

import numpy as np
X = np.array([1,0,0])
Y = X
X = 2*X
print Y
Run Code Online (Sandbox Code Playgroud)

Y 还是 array([1,0,0])

到底是怎么回事?

Nul*_*man 8

想一想:python中的等号分配引用.

Y = X 使Y指向X指向的相同地址

X[0] = 2 使x [0]指向2

X = 2*X 使X指向一个新的东西,但Y仍然指向原始X的地址,所以Y不变

这不完全正确,但它足够接近理解原则


Wil*_*sem 5

这是因为X并且Y同一个对象的引用,np.array([1,0,0])这意味着无论调用是通过 X或完成的Y,结果都是相同的,但更改一个引用,则无效.

如果你写:

X = np.array([1,0,0])
Y = X
Run Code Online (Sandbox Code Playgroud)

基本上什么情况是,有两个局部变量 XY同一个对象.所以内存看起来像:

     +--------+
Y -> |np.array| <- X
     +--------+
     |[1,0,0] |
     +--------+
Run Code Online (Sandbox Code Playgroud)

现在如果你这样做X[0] = 2基本上是短的:

X.__setitem__(0,2)
Run Code Online (Sandbox Code Playgroud)

所以你在对象上调用一个方法.所以现在内存看起来像:

     +--------+
Y -> |np.array| <- X
     +--------+
     |[2,0,0] |
     +--------+
Run Code Online (Sandbox Code Playgroud)

如果你写的话:

X = 2*X
Run Code Online (Sandbox Code Playgroud)

首先2*X评估.现在2*X简称:

X.__rmul__(2)
Run Code Online (Sandbox Code Playgroud)

(Python的首先查找,如果2支持__mul__X,但由于2将引发一个NotImplementedException),Python将回退到X.__rmul__).现在X.__rmul__ 不改变X:它保持X原样,但构造一个新数组并返回它.X抓住现在引用该数组的新数组.

它创建一个新array对象:array([4, 0, 0])然后X 引用该新对象.所以现在内存看起来像:

     +--------+         +--------+
Y -> |np.array|     X ->|np.array|
     +--------+         +--------+
     |[2,0,0] |         |[4,0,0] |
     +--------+         +--------+
Run Code Online (Sandbox Code Playgroud)

但正如您所看到的,Y仍然引用旧对象.