将指针转换为cython中类的实例
我用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
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)