我不知道您所说的“调用值”或“而不是内存地址”是什么意思,或者……您问题的大部分文本。
但问题很简单。您一遍又一遍地附加相同的数组,而不是创建新数组。
如果你想创建一个新数组,你必须明确地这样做。这是微不足道的;只需将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)
但这可以大大简化。
首先,与其创建一个包含 1 个零的数组然后替换那个零,为什么不直接创建一个包含您想要的元素的数组?
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++ 非常不同,C++ 中的变量是类型化的内存位置,而对象位于这些内存位置。这意味着 Python 中没有“复制构造函数”或“赋值运算符”或类似的东西。当您编写a = b 时,这意味着a 现在是与b 具有相同值的另一个名称。如果你想要一份副本,你必须明确要求一份副本。
现在,如果您看看 CPython 如何在后台实现事物:
- CPython 解释器将所有对象表示为指向
PyObject 结构的指针,这些结构始终在堆上分配。
- 变量只是
dict 中的字符串键,由模块(对于全局变量)、实例(对于属性)或其他拥有。 dict 中的值与其他对象一样。这意味着,在幕后,实际上存储在哈希表中的是指向键中变量名称的字符串对象的指针,以及指向您在值中分配的任何值的指针。
- 有一个针对局部变量的特殊优化,涉及存储在框架上的对象指针数组,但您通常不必担心这一点。
- 闭包捕获还有另一个特殊技巧,涉及指向单元对象的指针,这些对象包含指向实际对象的指针,您不必经常担心这一点。
如您所见,考虑指针更难理解,并且可能会产生误导,除非您真的关心 CPython 的幕后工作原理。