Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/136.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Cython:如何获得';实际Python类型';(类型代码/数据类型)来自C级类型_Python_C++_C_Numpy_Cython - Fatal编程技术网

Cython:如何获得';实际Python类型';(类型代码/数据类型)来自C级类型

Cython:如何获得';实际Python类型';(类型代码/数据类型)来自C级类型,python,c++,c,numpy,cython,Python,C++,C,Numpy,Cython,我想为使用ctypedef定义的memoryview分配堆栈内存,并将其作为numpy ndarray返回。讨论了一些分配方法,但关键是我不知道如何通过编程将自定义ctypedef映射到分配所需的相应numpy dtype或Python类型代码 例如: from cython cimport view import numpy as np ctypedef int value_type # actual type subject to change # np.empty require

我想为使用ctypedef定义的memoryview分配堆栈内存,并将其作为numpy ndarray返回。讨论了一些分配方法,但关键是我不知道如何通过编程将自定义ctypedef映射到分配所需的相应numpy dtype或Python类型代码

例如:

from cython cimport view
import numpy as np

ctypedef int value_type    # actual type subject to change

# np.empty requires me knowing that Cython int maps to np.int32
def test_return_np_array(size_t N):
    cdef value_type[:] b = np.empty(N, dtype=np.int32)
    b[0]=12                  # from ctypedef int ^
    return np.asarray(b)
# or, Cython memoryview requires the type code 'i'
def test_return_np_array(size_t N):
    cdef value_type[:] b = view.array(shape=(N,), itemsize=sizeof(int), format="i")
    b[0]=12                                                 # from ctypedef int ^
    return np.asarray(b)
我使用的是typedef,这样我就可以灵活地更改实际的数据类型(比如从
int
long
),而不必修改所有代码

在纯Python中,类型检查很容易:

value_type = int
print(value_type is int)    # True
print(value_type is float)  # False
在numpy中,这也可以通过将数据类型参数化为字符串来轻松实现,如
value\u type=“int32”
然后调用
np.empty(N,dtype=value\u type)
。使用我的ctypedef,Cython不会编译
np.empty(N,dtype=value\u type)
,并抱怨“'value\u type'不是常量、变量或函数标识符”。有可能在编译时实现这样的功能吗

用户不必管理返回的内存,因此
malloc
将不是一个选项


我使用C++向量来生成一个黑客:向量[ValueSyType ](n).DATA()/Cuth>,但这似乎会导致内存错误。 从C的角度来看,int32不是一种类型,而是一个Python对象,它必须在运行时创建,不能在编译时创建

最可靠的方法可能是这个技巧(有关详细信息的解释,请参见此):

其优点是,Cython基础设施用于映射,不需要手动进行容易出错的工作


一种不那么神秘但更容易出错的方法:您可以通过在加载模块时在运行时调用的函数来选择正确的类型:

%%cython
import numpy as np

ctypedef int value_type 

SIGNED_NUMPY_TYPE_MAP = {2 : np.int16, 4 : np.int32, 8 : np.int64}
SIGNED_NUMPY_TYPE = SIGNED_NUMPY_TYPE_MAP[sizeof(value_type)]

def zeros(N):
    return np.zeros(N, dtype=SIGNED_NUMPY_TYPE)
现在:

>>> print(zeros(1).dtype)
int32
int
更改为
long-long
将导致拾取
np.int64

类似的方法也可用于内存视图


正如您所指出的,Cython教程建议手动映射类型,例如:

ctypedef np.int32_t value_type
SIGNED_NUMPY_TYPE = np.int32
然后根据需要手动更改这两个选项。对于较小的程序和原型,这种简单的解决方案可能是最好的。但是,有一些考虑因素可能需要更稳健的方法:

  • 当两个定义相邻放置时,很容易看出它们必须一起更改。对于更复杂的程序,这两个定义可以放在不同的pxd或pyx文件中,然后这只是一个时间问题,直到中断为止

  • 只要使用固定大小的类型(
    int32
    int64
    ),相应的numpy类型就显而易见。但是对于
    int
    long
    等类型,很难判断:

    • int
      只能保证至少有2个字节,且不超过
      long
      。编译器可以决定选择哪种大小,可能有点担心没有保证,但是通常的怀疑者(gcc、cland、icc和msvc)选择4字节作为通常的体系结构

    • long
      已经是一个陷阱:gcc选择Linux64为8字节,但在msvc中
      long
      只有4字节长,因此在不知道将使用哪种编译器的情况下,不能事先在
      np.int32
      np.int64
      之间进行选择

    • 对于
      long
      的情况,有
      np.int
      ,这非常令人困惑,因为人们希望
      np.int
      映射到
      int
      ,而不是
      long
      !但是在Linux64/gcc上,
      np.int.itemsize
      是8个字节,但是
      int
      只有4个字节长。另一方面,在Windows64/msvc上,
      np.int
      int
      都是4个字节


我的解决方法是手动定义运行时类型和相应的编译时类型,如
value\u type=np.int32
ctypedef np.int32\u t value\u type\t
(可以轻松更改为
value\u type=np.int64
ctypedef np.int64\u value\u type
),基于
/Cython/Includes/numpy/\uuuu init\uuuu.pxd
中的映射。你是对的,这是最简单的解决方案。我更新了我的答案,考虑了一些因素,这解释了为什么一个更健壮的方法可能值得费心。
>>> print(zeros(1).dtype)
int32
ctypedef np.int32_t value_type
SIGNED_NUMPY_TYPE = np.int32