我对下面代码的行为有点困惑,想知道是否有人可以解释这一点。基本上,我有一个名为
mat
的矩阵,它是一个 numpy ndarray
。我使用 mat.diagonal()
获取它的对角线并将其分配给变量 diag
。我把mat
的所有对角线值都改为100。现在我发现diag
的值也全部改为100,这似乎表明diag
直接引用了mat
中的元素。然而,当我检查 dia
g 中第一个元素的内存地址并将其与 mat
的内存地址进行比较时,它们是不同的。正确的看待这个问题的方法是什么?
import numpy as np
import pandas as pd
mat_df = pd.DataFrame(data=[[1,2,3], [4,5,6], [7,8,9]])
print(mat_df)
mat = mat_df.values
diag = mat.diagonal()
print(diag)
diag_loc = np.diag_indices_from(mat)
mat[diag_loc] = 100
print(diag)
print(diag[0])
print(id(diag[0]))
print(mat[0][0])
print(id(mat[0][0]))
mat
:
0 1 2
0 1 2 3
1 4 5 6
2 7 8 9
diag
:
[1 5 9]
diag
的值会因 mat
的变化而变化:
[100 100 100]
diag
的第一个值:
100
及其地址
139863357577488
mat的第一个值:
100
及其地址
139863376059664
您无法通过
id
知道地址。首先, id
不返回地址(尽管如此,CPython 实现使用内存地址来构建 id
,这只是一种实现,并且本身不是地址)。其次,这只是 python 对象的地址(在您的情况下是包装 numpy.int64
的地址)。
该 python 对象只是为了包装任何 numpy 函数(对 python 不透明:python 不知道它们何时应该返回相同的值)返回而构建。
您可以做一些简单的实验来说服自己,您的
id
毫无意义
id(diag[0])
# 139729998312368
id(diag[0])
# 139730045496016
看,即使是连续两次完全相同的调用也不会返回相同的 id!
diag[0]
是对 numpy 的 diag.__getitem__(0)
的调用。包装到每次都不同的 python 容器中,就像调用任何函数 f(0)
的结果一样,没有理由假设每个相同的调用都会返回完全相同的结果。
因此,如果你想知道实际的
int64
存储在哪里,你不能问 python(及其 id
函数),因为这不仅是现在 id
的用途,而且更重要的是,python 不这样做我不知道。 int64
存储在哪里是 numpy 库的内部问题。所以你需要问numpy。
最好的方法是使用
base
恕我直言。
diag.base
#array([[100, 2, 3],
# [ 4, 100, 6],
# [ 7, 8, 100]])
diag.base is mat.base
# True
但是,如果您坚持拥有某种地址,您也可以
diag.ctypes.data
# 61579664
mat.ctypes.data
# 61579664
或者,有关查看哪些数据以及如何通过数组查看数据的更完整信息
mat.__array_interface__
# {'data': (61579664, False), 'strides': (8, 24), 'descr': [('', '<i8')], 'typestr': '<i8', 'shape': (3, 3), 'version': 3}
diag.__array_interface__
# {'data': (61579664, True), 'strides': (32,), 'descr': [('', '<i8')], 'typestr': '<i8', 'shape': (3,), 'version': 3}
展示了两者如何使用相同的“数据”但使用不同的“步幅”和“形状”来使用它。