Почему не копирование массива numpy изменяет атрибут данных? - PullRequest
4 голосов
/ 08 апреля 2020

Как показывает мой MWE ниже, вызов np.array(a, copy=False) для существующего массива a возвращает что-то, что ведет себя точно так, как ожидалось, за исключением , что атрибуты .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>

Ответы [ 2 ]

0 голосов
/ 08 апреля 2020
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}
0 голосов
/ 08 апреля 2020

Если вы введете:

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) возвращает целое число и идентификатор (b), а также их адрес памяти не то же самое, хотя их значения равны.

Если вам нужна шестнадцатеричная память:

hex(id(a))

Кроме того, с NumPy do c: numpy .ndarray.data (я действительно не знаю, почему это .data полезно, но оно существует)

...