在cython中定义不同的对象时,内存视图将返回相同的地址。但是,数组本身在被索引后将被修改。
我有用cython编写的基类和派生类。我注意到,当我对类应用多处理时,底层缓冲区在不同的进程中发生了变化,这不是故意的。在酸洗过程中,我编写了一个简单的__reduce__方法和__deepcopy__方法来重建原始对象。为了清楚起见,我将下面的代码的复杂性降低了。现在我的问题是,为什么memoryviews返回相同的地址?另外,为什么即使内存视图相同,numpy数组本身也会正确更改
#distutils: language=c++
import numpy as np
cimport numpy as np
cdef class Temp:
cdef double[::1] inp
def __init__(self, inp):
print(f'id of inp = {id(inp)}')
self.inp = inp
cdef np.ndarray x = np.ones(10)
cdef Temp a = Temp(x)
cdef Temp b = Temp(x)
cdef Temp c = Temp(x.copy())
b.inp[0] = -1
c.inp[2] = 10
print(f'id of a.inp = {id(a.inp)}\nid of b.inp = {id(b.inp))}\nid of c.inp = {id(c.inp)}')
print(f'id of a.inp.base = {id(a.inp.base)}\nid of b.inp.base = {id(b.inp.base))}\nid of c.inp.base = {id(c.inp.base)}')
print('a.inp.base',a.inp.base)
print('b.inp.base',b.inp.base) # expected to be the same as a
print('c.inp.base',c.inp.base) # expected to be different to a/b
输出:
id of inp = 139662709551872
id of inp = 139662709551872
id of inp = 139662709551952
id of a.inp = 139662450248672
id of b.inp = 139662450248672
id of c.inp = 139662450248672
id of a.inp.base = 139662709551872
id of b.inp.base = 139662709551872
id of c.inp.base = 139662709551952
a.inp.base [-1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]
b.inp.base [-1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]
c.inp.base [ 1. 1. 10. 1. 1. 1. 1. 1. 1. 1.]
答案 0 :(得分:2)
我们所谓的类型化内存视图不是一个单独的类:根据上下文(Cython代码,纯Python代码),它会在后台更改其身份。
所以让我们开始吧
%%cython
cdef class Temp:
cdef double[::1] inp
这里double[::1] inp
的类型为__Pyx_memviewslice
,它不是Python对象:
typedef struct {
struct {{memview_struct_name}} *memview;
char *data;
Py_ssize_t shape[{{max_dims}}];
Py_ssize_t strides[{{max_dims}}];
Py_ssize_t suboffsets[{{max_dims}}];
} {{memviewslice_name}};
当我们致电id(self.inp)
时会发生什么?显然,id
是纯Python函数,因此必须从self.inp
创建一个新的临时python对象(内存视图)(仅能够调用id
)并直接销毁然后。临时Python对象的创建是通过__pyx_memoryview_fromslice
完成的。
知道,为什么ID相等很容易解释:尽管它们是不同的对象,但临时内存视图具有相同的地址(因此也具有相同的id
,这是CPython的实现细节),因为内存会被CPython反复使用。
在Python中到处都有类似的场景,这里是an example for method-objects,甚至更简单的场景:
class A:
pass
# the life times of temporary objects don't overlap, so the ids can be the equal
id(A())==id(A())
# output: True
# the life times of objects overlap, so the id cannot be equal
a,b=A(), A()
id(a)==id(b)
# output: False
因此,简而言之:您的期望是,相同的id
表示相同的对象是错误的。只有当对象的寿命重叠时,这种假设才成立。