【问题标题】:How can I call values of a np.array rather than memory address? [duplicate]如何调用 np.array 的值而不是内存地址? [复制]
【发布时间】:2018-11-27 19:59:03
【问题描述】:

在下面的代码中,我打算从一个空的列表开始 通过附加(随机)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])]

【问题讨论】:

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

标签: python arrays numpy


【解决方案1】:

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

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

如果你想创建一个新数组,你必须明确地这样做。这是微不足道的;只需将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 的幕后工作原理。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-03-13
    • 1970-01-01
    • 1970-01-01
    • 2020-04-23
    • 2016-04-08
    • 1970-01-01
    • 1970-01-01
    • 2017-12-11
    相关资源
    最近更新 更多