将指针转换为cython中类的实例

将指针转换为cython中类的实例,c,arrays,class,pointers,cython,C,Arrays,Class,Pointers,Cython,我用cython编写了一个类,我有一个方法可以检查类对象是否没有属性。如果文件存在,它将从文件中读取该对象,或者计算数组或内存视图的值,并将结果保存在文件中。以下是我的部分代码: from __future__ import division import numpy as np cimport numpy as np cimport cython from libc.stdio cimport FILE, fopen, fwrite, fscanf, fclose, stdout, stder

我用cython编写了一个类,我有一个方法可以检查类对象是否没有属性。如果文件存在,它将从文件中读取该对象,或者计算数组或内存视图的值,并将结果保存在文件中。以下是我的部分代码:

from __future__ import division
import numpy as np
cimport numpy as np
cimport cython
from libc.stdio cimport FILE, fopen, fwrite, fscanf, fclose, stdout, stderr

cdef extern from "math.h":
    double exp(double) nogil
    double log(double) nogil

cdef class NFW(object):
    cdef object ks, source_redshift
    cdef const char* path
    def __cinit__(self, char* path, double[::1] zs=None, *args):
        self.path=path
        if self.path==NULL:
           raise ValueError("Could not find a path to the file which contains the table of  diameter distances")
        if zs is None:
           raise ValueError("You must give an array !")
        self.source_redshift=zs

    @cython.cdivision(True)    
    @cython.boundscheck(False)
    @cython.wraparound(False)
    cdef void get_ks(self):
         cdef FILE* handle
         cdef Py_ssize_t i, nz
         nz  = len(self.source_redshift)
         cdef double* array[nz] 
         if not hasattr(self, 'ks'):  # does self.ks not exist?
            try:
               ## first, check for existing file, see if we can load in self.ks
               handle = fopen(self.path, "r")
               if handle == NULL:
                  raise ValueError("cannot open file {}".format(self.path))

               for i from nz > i >= 0:
                   fscanf(handle,"%f",&array[i])
               fclose(handle)
               self.ks= &array
            except IOError:

               self.ks = self.calculate_ks() 

    @cython.cdivision(True)    
    @cython.boundscheck(False)
    @cython.wraparound(False)
    cdef double[::1] calculate_ks(self):
         cdef Py_ssize_t i, nz
         nz  = len(self.source_redshift)
         cdef double[::1] k_s = np.zeros(nz,dtype=np.float64_t)

         for i from nz > i >= 0:         
             k_s[i]= log((1.+self.source_redshift[i])/(1.-self.source_redshift[i]))
         #write the calculated k_s in a file
         cdef FILE* handle=<FILE *>fopen(self.path,"wb")
         fwrite(k_s,sizeof(k_s),1,handle)
         fclose(handle)
         return k_s
来自未来进口部的

将numpy作为np导入
cimport numpy作为np
西姆波特赛顿酒店
来自libc.stdio cimport文件、fopen、fwrite、fscanf、fclose、stdout、stderr
“math.h”中的cdef外部变量:
双出口
双原木
cdef类NFW(对象):
cdef对象ks,源\红移
cdef常量字符*路径
定义(self,char*path,double[::1]zs=None,*args):
self.path=path
如果self.path==NULL:
raise VALUERROR(“找不到包含直径距离表的文件的路径”)
如果zs为无:
raise VALUERROR(“您必须提供一个数组!”)
self.source_redshift=zs
@cython.cdivision(真)
@cython.boundscheck(错误)
@cython.wrapparound(假)
cdef无效获取(自身):
cdef文件*句柄
cdef Py_ssize_t i,新西兰
nz=len(自源\红移)
cdef双*阵列[nz]
如果不是hasattr(self,“ks”):#self.ks不存在吗?
尝试:
##首先,检查现有文件,看看是否可以在self.ks中加载
handle=fopen(self.path,“r”)
如果handle==NULL:
raise VALUERROR(“无法打开文件{}”。格式(self.path))
对于来自新西兰的i>i>=0:
fscanf(句柄、%f、&数组[i])
fclose(手柄)
self.ks=&数组
除IOError外:
self.ks=self.calculate_ks()
@cython.cdivision(真)
@cython.boundscheck(错误)
@cython.wrapparound(假)
cdef double[::1]计算(自身):
cdef Py_ssize_t i,新西兰
nz=len(自源\红移)
cdef double[::1]k_s=np.zeros(nz,dtype=np.float64_t)
对于来自新西兰的i>i>=0:
k_s[i]=log((1.+self.source_redshift[i])/(1.-self.source_redshift[i]))
#将计算出的k_写入文件
cdef文件*handle=fopen(self.path,“wb”)
fwrite(k_s,sizeof(k_s),1,手柄)
fclose(手柄)
返回k_s
我对c不是很熟悉,我是一个cython初学者。我收到了以下错误消息,我不知道用指针数组读取cython中的文件并将其转换为类实例的最佳方法是什么。我应该强调的是,我正在寻找最快的方法来执行cython中的文件读取

Error compiling Cython file:
------------------------------------------------------------
...
    @cython.wraparound(False)
    cdef void get_ks(self):
         cdef FILE* handle
         cdef Py_ssize_t i, nz
         nz  = len(self.source_redshift)
         cdef double* array[nz] 
                             ^
------------------------------------------------------------

WLUtilities.pyx:413:30: Not allowed in a constant expression

Error compiling Cython file:
------------------------------------------------------------
...
                  raise ValueError("cannot open file {}".format(self.path))

               for i from nz > i >= 0:
                   fscanf(handle,"%f",&array[i])
               fclose(handle)
               self.ks= &array
                       ^
------------------------------------------------------------

WLUtilities.pyx:424:24: Cannot convert 'double *(*)[__pyx_v_nz]' to Python object

Error compiling Cython file:
------------------------------------------------------------
...
         k_s = np.zeros(nz,dtype=np.float64_t)
         for i from nz > i >= 0:         
             k_s[i]= self.__ks(self.source_redshift[i])
         #write the calculated k_s in a file
         cdef FILE* handle=<FILE *>fopen(self.path,"wb")
         fwrite(k_s,sizeof(k_s),1,handle)
                  ^
------------------------------------------------------------


WLUtilities.pyx:440:19: Cannot convert Python object to 'const void *'
编译Cython文件时出错: ------------------------------------------------------------ ... @cython.wrapparound(假) cdef无效获取(自身): cdef文件*句柄 cdef Py_ssize_t i,新西兰 nz=len(自源\红移) cdef双*阵列[nz] ^ ------------------------------------------------------------ WLUtilities.pyx:413:30:在常量表达式中不允许 编译Cython文件时出错: ------------------------------------------------------------ ... raise VALUERROR(“无法打开文件{}”。格式(self.path)) 对于来自新西兰的i>i>=0: fscanf(句柄、%f、&数组[i]) fclose(手柄) self.ks=&数组 ^ ------------------------------------------------------------ WLUtilities.pyx:424:24:无法将'double*(*)[\uuupyx\uv\unz]'转换为Python对象 编译Cython文件时出错: ------------------------------------------------------------ ... k_s=np.zero(nz,dtype=np.float64_t) 对于来自新西兰的i>i>=0: k_s[i]=self.\u ks(self.source\u redshift[i]) #将计算出的k_写入文件 cdef文件*handle=fopen(self.path,“wb”) fwrite(k_s,sizeof(k_s),1,手柄) ^ ------------------------------------------------------------ WLUtilities.pyx:440:19:无法将Python对象转换为“const void*” 此处:

         nz  = len(self.source_redshift)
         cdef double* array[nz] 
                             ^
------------------------------------------------------------

WLUtilities.pyx:413:30: Not allowed in a constant expression
由于您在python对象上调用了len,所以不清楚nz是否会在编译时被知道,这就是Cython在这里抱怨的原因。 比如:

     cdef double* array[5] 
将编译(当然这对您来说毫无用处,但关键是您必须在编译时了解nz,可能需要使用c函数来获得大小)。 在这里:

不能将地址分配给Python对象。类似的内容会取消对地址的引用,并将其内容转换为cython能够处理的内容:

       self.ks= np.array(<double[:5]> array[0])
您应该将您的memoryview转换为一个void ponter(语法可能很烦人,但cython就是这么用的):

fwrite(&k_-s[0],sizeof(k_-s),1,handle)
如果将代码中的行替换为上面的这些行,它将编译。同样,您必须使nz在编译时为人所知(您可以使用代码中的“5”进行测试)。使用cython进行强制转换有几种方法,我想到了一些,但您可能会找到更好的方法。

(如果此代码有一些小错误,并且无法立即正常工作,我深表歉意-我还没有实际测试过这一点。但是原理应该可以正常工作。)

最简单的方法不是使用双数组,而是使用MemoryView。访问元素的开销非常低(不比指针访问差太多,而且在执行IO时不太可能成为限制因素)。通过MemoryView,您可以使用所有标准python方法在运行时轻松地分配内存

代码如下,并附有一些注释

# omitted "cdivision" - you aren't actually doing any division so it doesn't matter
@cython.boundscheck(False)
@cython.wraparound(False)
cdef void get_ks(self):
     cdef FILE* handle
     cdef Py_ssize_t i, nz
     nz  = len(self.source_redshift)
     # Memory is managed by numpy. Alternatively you can use the python array module
     # The "1" in "::1" promises that it's genuinely continuous (I think) and so should speed things up
     cdef double[::1] array = np.empty((nz,))
     if not hasattr(self, 'ks'):  # does self.ks not exist?
        try:
           ## first, check for existing file, see if we can load in self.ks
           handle = fopen(self.path, "r")
           if handle == NULL:
              raise ValueError("cannot open file {}".format(self.path))

           # I've changed this to "range" because it's a little more iomatic
           # change it back if you like! It shouldn't make much difference
           for i in range(nz-1,-1,-1):
               # &array[i] should still work with a memoryview
               # Changed to 'lf' since we're using doubles
               fscanf(handle,"%lf",&array[i])
           fclose(handle) # does this want to be in "finally" to ensure it gets done?
           self.ks= array # no need to take address - this should just work
        except IOError:

           self.ks = self.calculate_ks() 
“calculate_ks”中的错误可能会被处理为

cdef double* array_as_doubles = &ks[0]
fwrite(<void*>array_as_doubles, # cast to void
       sizeof(double),len(ks), # calculate length properly! 
       handle) 
cdef double*数组作为double=&ks[0]
fwrite(数组#为#的两倍,#强制无效
sizeof(双精度),len(ks),#正确计算长度
 fwrite(<void*> &k_s[0],sizeof(k_s),1,handle)
# omitted "cdivision" - you aren't actually doing any division so it doesn't matter
@cython.boundscheck(False)
@cython.wraparound(False)
cdef void get_ks(self):
     cdef FILE* handle
     cdef Py_ssize_t i, nz
     nz  = len(self.source_redshift)
     # Memory is managed by numpy. Alternatively you can use the python array module
     # The "1" in "::1" promises that it's genuinely continuous (I think) and so should speed things up
     cdef double[::1] array = np.empty((nz,))
     if not hasattr(self, 'ks'):  # does self.ks not exist?
        try:
           ## first, check for existing file, see if we can load in self.ks
           handle = fopen(self.path, "r")
           if handle == NULL:
              raise ValueError("cannot open file {}".format(self.path))

           # I've changed this to "range" because it's a little more iomatic
           # change it back if you like! It shouldn't make much difference
           for i in range(nz-1,-1,-1):
               # &array[i] should still work with a memoryview
               # Changed to 'lf' since we're using doubles
               fscanf(handle,"%lf",&array[i])
           fclose(handle) # does this want to be in "finally" to ensure it gets done?
           self.ks= array # no need to take address - this should just work
        except IOError:

           self.ks = self.calculate_ks() 
cdef double* array_as_doubles = &ks[0]
fwrite(<void*>array_as_doubles, # cast to void
       sizeof(double),len(ks), # calculate length properly! 
       handle)