关于重塑和视图的 Numpy ndarray 数据所有权问题
Numpy ndarray data ownership problem on reshape and view
我对 numpy 中的所有权机制感到困惑。
import numpy as np
a = np.arange(10)
a.flags.owndata # True
id(a) # 140289740187168
前四行很明显,变量a
拥有id为140289740187168
的数据。
b = a
c = a.view()
d = a.reshape((2, 5))
print(b.flags.owndata, b.base, id(b.base)) # True None 94817978163056
print(c.flags.owndata, c.base, id(c.base)) # False [0 1 2 3 4 5 6 7 8 9] 140289740187168
print(d.flags.owndata, d.base, id(d.base)) # False [0 1 2 3 4 5 6 7 8 9] 140289740187168
id(None) # 94817978163056
变量 c,d
都是从 a
的“浅层”复制,所以 none 都有自己的数据。 b
是 a
并拥有数据(与 a
共享)。
a = a.view()
print(id(a)) # 140289747003632
print(a.flags.owndata, a.base, id(a.base)) # False [0 1 2 3 4 5 6 7 8 9] 140289740187168
但是,将 a
的视图分配给 a
会创建一个新的 id 140289747003632
变量,并将数据所有权留给之前旧的 a
id 140289740187168
.
问题是,既然旧的a
已经被新的a
超载了,那么将数据所有权转移给新的a
会更合理。为什么旧 a
仍然保留数据所有权?
b = a
b
是 a
,只是同一对象的不同名称。那甚至不是副本。
这些是 views
。视图是一个新数组,但它使用相同的数据缓冲区(如 base
:
c = a.view()
d = a.reshape((2, 5))
我喜欢用__array_interface__
来看一个数组的基本属性:
In [210]: a = np.arange(10)
In [211]: a.__array_interface__
Out[211]:
{'data': (43515408, False),
'strides': None,
'descr': [('', '<i8')],
'typestr': '<i8',
'shape': (10,),
'version': 3}
data[0]
是 a
的值或数据存储位置的某种表示形式。
A view
将具有相同的 'data'(可能有偏移量)。否则 view
有自己的 strides
和 shape
。它是一个共享 base
:
的新数组对象
In [212]: d = a.reshape((2,5))
In [213]: d.__array_interface__
Out[213]:
{'data': (43515408, False),
'strides': None,
'descr': [('', '<i8')],
'typestr': '<i8',
'shape': (2, 5),
'version': 3}
将view
分配给a
不会改变原始数组或数据缓冲区。原始 a
数组对象及其数据缓冲区仍存在于内存中。
In [214]: a = a.view()
In [216]: a.__array_interface__['data']
Out[216]: (43515408, False)
如果 numpy
'updated' 如您所建议的 a.base
,它还必须针对原始 a
的所有视图更新它,例如 d
.
In [218]: id(a)
Out[218]: 139767778126704
In [219]: id(a.base)
Out[219]: 139768132465328
In [220]: id(d.base)
Out[220]: 139768132465328
虽然 python 和 numpy
维护某种引用计数以确定哪些对象是垃圾,但 numpy
不维护 views
已创建内容的记录.也就是说,虽然 d.base
link 是 d
到 a
,但没有 link 相反的
我对 numpy 中的所有权机制感到困惑。
import numpy as np
a = np.arange(10)
a.flags.owndata # True
id(a) # 140289740187168
前四行很明显,变量a
拥有id为140289740187168
的数据。
b = a
c = a.view()
d = a.reshape((2, 5))
print(b.flags.owndata, b.base, id(b.base)) # True None 94817978163056
print(c.flags.owndata, c.base, id(c.base)) # False [0 1 2 3 4 5 6 7 8 9] 140289740187168
print(d.flags.owndata, d.base, id(d.base)) # False [0 1 2 3 4 5 6 7 8 9] 140289740187168
id(None) # 94817978163056
变量 c,d
都是从 a
的“浅层”复制,所以 none 都有自己的数据。 b
是 a
并拥有数据(与 a
共享)。
a = a.view()
print(id(a)) # 140289747003632
print(a.flags.owndata, a.base, id(a.base)) # False [0 1 2 3 4 5 6 7 8 9] 140289740187168
但是,将 a
的视图分配给 a
会创建一个新的 id 140289747003632
变量,并将数据所有权留给之前旧的 a
id 140289740187168
.
问题是,既然旧的a
已经被新的a
超载了,那么将数据所有权转移给新的a
会更合理。为什么旧 a
仍然保留数据所有权?
b = a
b
是 a
,只是同一对象的不同名称。那甚至不是副本。
这些是 views
。视图是一个新数组,但它使用相同的数据缓冲区(如 base
:
c = a.view()
d = a.reshape((2, 5))
我喜欢用__array_interface__
来看一个数组的基本属性:
In [210]: a = np.arange(10)
In [211]: a.__array_interface__
Out[211]:
{'data': (43515408, False),
'strides': None,
'descr': [('', '<i8')],
'typestr': '<i8',
'shape': (10,),
'version': 3}
data[0]
是 a
的值或数据存储位置的某种表示形式。
A view
将具有相同的 'data'(可能有偏移量)。否则 view
有自己的 strides
和 shape
。它是一个共享 base
:
In [212]: d = a.reshape((2,5))
In [213]: d.__array_interface__
Out[213]:
{'data': (43515408, False),
'strides': None,
'descr': [('', '<i8')],
'typestr': '<i8',
'shape': (2, 5),
'version': 3}
将view
分配给a
不会改变原始数组或数据缓冲区。原始 a
数组对象及其数据缓冲区仍存在于内存中。
In [214]: a = a.view()
In [216]: a.__array_interface__['data']
Out[216]: (43515408, False)
如果 numpy
'updated' 如您所建议的 a.base
,它还必须针对原始 a
的所有视图更新它,例如 d
.
In [218]: id(a)
Out[218]: 139767778126704
In [219]: id(a.base)
Out[219]: 139768132465328
In [220]: id(d.base)
Out[220]: 139768132465328
虽然 python 和 numpy
维护某种引用计数以确定哪些对象是垃圾,但 numpy
不维护 views
已创建内容的记录.也就是说,虽然 d.base
link 是 d
到 a
,但没有 link 相反的