簡體   English   中英

cython中的memoryview的地址相同,但是指向不同的對象

[英]Address of memoryviews in cython are the same but point to different object

問題

在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.]

我們所謂的類型化內存視圖不是一個單獨的類:根據上下文(Cython代碼,純Python代碼),它在后台更改了其標識。

因此,讓我們開始

%%cython 
cdef class Temp:
    cdef double[::1] inp

這里的double[::1] inp __Pyx_memviewslice__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-object(內存視圖)(僅能調用id ),然后直接銷毀。 臨時Python對象的創建是通過__pyx_memoryview_fromslice完成的。

知道這些ID為何相等很容易解釋:盡管它們是不同的對象,但臨時內存視圖具有相同的地址(因此也具有相同的id ,這是CPython的實現細節),因為在再由CPython進行。

Python中到處都有類似的場景,這是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表示相同的對象是錯誤的。 僅當對象的壽命重疊時,此假設成立。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM