【问题标题】:How come not-copying a numpy array changes the data attribute?为什么不复制 numpy 数组会更改数据属性?
【发布时间】:2020-07-20 22:56:57
【问题描述】:

正如我下面的 MWE 所示,在现有数组 a 上调用 np.array(a, copy=False) 返回的行为与预期完全相同,除了 .data 属性似乎不同。这怎么可能?

>>> a                               # My original array
array([2])
>>> b = np.array(a, copy=False)     # Not-a-copy of the original array
>>> b is a                          # The Python objects seem to be identical
True
>>> b.data is a.data                # But their .data attributes aren't??
False
>>> a.data
<memory at 0x7f82ebd757c8>
>>> b.data
<memory at 0x7f82ebd75888>
>>> b 
array([2])
>>> a
array([2])
>>> a[:] = 3                        # Changing a indeed also changes b
>>> a
array([3])
>>> b
array([3])
>>> a.data
<memory at 0x7f82ebd757c8>
>>> b.data
<memory at 0x7f82ebd75888>

编辑

在玩的时候,我什至发现.data属性在看的时候发生了变化!

>>> a.data is a.data        # a.data isn't equal to itself?!
False
>>> a.data
<memory at 0x7f82ebd75948>
>>> a.data
<memory at 0x7f82ebd75888>  # A different value than a minute ago
>>> a.data
<memory at 0x7f82ebd75948>
>>> a.data
<memory at 0x7f82ebd75888>
>>> a.data
<memory at 0x7f82ebd75948>
>>> a.data
<memory at 0x7f82ebd75888>
>>> a.data
<memory at 0x7f82ebd75948>
>>> a.data
<memory at 0x7f82ebd75888>
>>> a.data
<memory at 0x7f82ebd75948>

【问题讨论】:

    标签: python arrays numpy numpy-ndarray


    【解决方案1】:

    如果你输入:

    help(a.data)
    

    您会发现它并没有完全按照您的预期返回:

    class memoryview(object)
     |  memoryview(object)
     |  
     |  Create a new memoryview object which references the given object.
     |  
     |  Methods defined here:
     |  
    
    

    它创建一个引用该对象的内存视图。如果你想要内存地址使用id:

    id(a) == id(b)
    True
    

    注意:

    id(a) is id(b)
    False
    

    因为id(a) 也返回一个整数和 id(b) 并且它们的内存地址相同,尽管它们的值是相同的。

    如果你想要十六进制内存:

    hex(id(a))
    

    另外,来自 NumPy 文档:numpy.ndarray.data(我真的不知道为什么这个 .data 有用但它确实存在)

    【讨论】:

    • 我认为您误读了文档字符串。文档说调用 memoryview 类会创建一个新的 memoryview 对象。并不是说访问 numpy 数组的 data 属性会创建一个新的 memoryview 对象。
    • 不是我原来的问题的一部分,但我正在寻找的内存地址是底层数组的地址,而不是 python 数组对象的地址。 id 函数不适用于此:id(a.view(np.ndarray)) == id(a) 返回 False
    • 确实是这样,没想到为什么每次都在变化,但我猜这是因为返回的python缓冲区对象,我会更多地搜索它docs.python.org/3.0/c-api/buffer.html@Martin
    • 您使用的视图错误,应该是:id(a.view(type=np.ndarray)) == id(a)` 即True您编写 dtype 将是 np.ndarray,因此将创建另一个数组 docs.scipy.org/doc/numpy/reference/generated/…
    • id(a) is not id(b) 因为创建了两个不同的 int 对象。这与底层数组无关。
    【解决方案2】:
    In [33]: a = np.array([2])                                                                             
    In [34]: b = np.array(a, copy=False)  
    

    __array_interface__ 字典是检查共享数据缓冲区的一种很好的人类可读方法。

    In [36]: a.__array_interface__                                                                         
    Out[36]: 
    {'data': (69508768, False),
     'strides': None,
     'descr': [('', '<i8')],
     'typestr': '<i8',
     'shape': (1,),
     'version': 3}
    In [37]: b.__array_interface__                                                                         
    Out[37]: 
    {'data': (69508768, False),
     'strides': None,
     'descr': [('', '<i8')],
     'typestr': '<i8',
     'shape': (1,),
     'version': 3}
    

    a.data 可用于创建一个新数组,但在其他方面不是很有用。对于大多数用途来说,即使是这种用法也太低级了:

    In [44]: c = np.ndarray(shape=(1,1), dtype=int, buffer=a.data)                                         
    In [45]: c                                                                                             
    Out[45]: array([[2]])
    In [46]: c.__array_interface__                                                                         
    Out[46]: 
    {'data': (69508768, False),
     'strides': None,
     'descr': [('', '<i8')],
     'typestr': '<i8',
     'shape': (1, 1),
     'version': 3}
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-24
      • 1970-01-01
      • 2021-11-03
      • 1970-01-01
      • 2020-09-24
      • 2019-10-05
      相关资源
      最近更新 更多