Python 如何调用np.array的值而不是内存地址?

Python 如何调用np.array的值而不是内存地址?,python,arrays,numpy,Python,Arrays,Numpy,在下面的代码中,我打算创建一个从空列表开始的列表 通过附加(随机)numpy数组。对于一个临时变量,我初始化了一个numpy数组变量“sample_pt”,它作为一个临时变量来保存一个(随机)numpy数组。虽然我希望有一个随机numpy数组的列表,但输出是一个填充了相同(最终)numpy数组的列表。我怀疑通过“变量名”调用numpy数组会返回其内存地址。我走的方向对吗,或者有什么好知道的吗 [守则] import numpy as np sample_pt=np.array([0.]) #

在下面的代码中,我打算创建一个从空列表开始的列表 通过附加(随机)numpy数组。对于一个临时变量,我初始化了一个numpy数组变量“sample_pt”,它作为一个临时变量来保存一个(随机)numpy数组。虽然我希望有一个随机numpy数组的列表,但输出是一个填充了相同(最终)numpy数组的列表。我怀疑通过“变量名”调用numpy数组会返回其内存地址。我走的方向对吗,或者有什么好知道的吗

[守则]

import numpy as np

sample_pt=np.array([0.]) # initial point
sample_list=[]
number_iter=3

for _ in range(number_iter):
    sample_pt[0]=np.random.randn()
    sample_list.append(sample_pt)
    print(sample_list)
[输出]

[array([-0.78614157])]
[array([0.7172035]), array([0.7172035])]
[array([0.47565398]), array([0.47565398]), array([0.47565398])]

我不知道你所说的“调用值”,或者“而不是内存地址”,或者…你问题的大部分文本是什么意思

但问题很简单。您正在一次又一次地追加相同的数组,而不是创建新的数组

如果要创建一个新数组,必须显式地创建。这是琐碎的事;只需将
np.array
构造函数移动到循环中,如下所示:

sample_list=[]
number_iter=3

for _ in range(number_iter):
    sample_pt=np.array([0.]) # initial point
    sample_pt[0]=np.random.randn()
    sample_list.append(sample_pt)
    print(sample_list)
但这可以大大简化

首先,与其创建一个0为1的数组,然后替换该0,为什么不创建一个所需元素的数组呢

sample_pt = np.array([np.random.randn()])
或者,更好的是,为什么不让
np.random
为您构建数组呢

sample_pt = np.random.randn(1)
在这一点上,您可以用列表替换整个内容:

number_iter = 3
sample_list = [np.random.randn(1) for _ in range(number_iter)]
或者,更好的是,为什么不制作一个3x1数组,而不是一个由3个单元素数组组成的列表

number_iter = 3
sample_array = np.random.randn((number_iter, 1))
如果出于某种原因确实需要将其更改为一个包含3个数组的列表,您可以随时稍后在其上调用
list

sample_list = list(sample_array)
…或从一开始:

sample_list = list(np.random.randn((number_iter, 1)))

同时,我认为您误解了值和变量在Python中的工作方式

首先,暂时忘记“内存地址”:

  • 对象是堆中某个位置的值,具有类型。你不在乎在哪里
  • 变量没有内存地址或类型;它们只是某些名称空间(全局、局部、某些实例的属性等)中引用某个值的名称
注意,这与C++不同,变量是类型化的内存位置,对象位于这些内存位置。这意味着Python中没有“复制构造函数”或“赋值运算符”之类的东西。当您编写
a=b
时,这意味着
a
现在是与
b
相同值的另一个名称。如果你想要一份副本,你必须明确要求一份副本

现在,如果你看看CPython是如何在引擎盖下实现的:

  • CPython解释器将所有对象表示为指向
    PyObject
    结构的指针,这些结构总是在堆上分配的
  • 变量只是
    dict
    中的字符串键,由模块(用于全局变量)、实例(用于属性)或其他任何内容拥有。
    dict
    中的值与其他对象一样。这意味着,在幕后,哈希表中实际存储的是指向键中变量名的字符串对象的指针,以及指向在值中指定的任何值的指针
  • 对于局部变量有一种特殊的优化,包括存储在框架上的一组对象指针,但通常不必担心这一点
  • 闭包捕获还有另一个特殊的技巧,包括指向单元格对象的指针,这些指针包含指向实际对象的指针,您甚至不必经常担心这些

正如您所见,思考指针更难理解,而且可能会产生误导,除非您真正关心CPython在幕后是如何工作的。

重复的一点是,在列表中附加相同的可变对象是危险的。如果使用列表附加,则每次创建一个新对象。