我遇到的问题是我的ctypes代码在python2中工作但在python3中失败。
我失败的函数是arrptr_to_np,它试图获取在外部c库中创建的数组并将其加载到numpy数组中。
该功能如下所示
def arrptr_to_np(c_arrptr, shape, arr_t, dtype):
"""
Casts an array pointer from C to numpy
Args:
c_arrpt (uint64): a pointer to an array returned from C
shape (tuple): shape of the underlying array being pointed to
arr_t (PyCSimpleType): the ctypes datatype of c_arrptr
dtype (dtype): numpy datatype the array will be to cast into
"""
byte_t = ctypes.c_char
itemsize_ = dtype().itemsize
dtype_t = byte_t * itemsize_
dtype_ptr_t = C.POINTER(dtype_t) # size of each item
typed_c_arrptr = c_arrptr.astype(int)
c_arr = C.cast(typed_c_arrptr, dtype_ptr_t) # cast to ctypes
np_arr = np.ctypeslib.as_array(c_arr, shape)
np_arr.dtype = dtype
return np_arr
这些是使用
的示例中的变量值varname - value - type(var)
c_arrptr - 20622304 - numpy.uint64
形状 - (506,6) - 元组
arr_t - numpy.ctypeslib.ndpointer_< f4_2d_ALIGNED_C_CONTIGUOUS_WRITEABLE - _ctypes.PyCSimpleType
dtype - np.float32 - np.float32
python2和python3版本之间的相同(当然除了指针的值,但它仍然是uint64)
当我执行该函数时,它在python2中按预期工作。 但是,在python3中,我在这一行上收到错误
c_arr = C.cast(typed_c_arrptr, dtype_ptr_t) # cast to ctypes
错误是ArgumentError
/usr/lib/python3.4/ctypes/__init__.py in cast(obj, typ)
487 def cast(obj, typ):
--> 488 return _cast(obj, obj, typ)
489
ArgumentError: argument 1: <class 'TypeError'>: wrong type
During handling of the above exception, another exception occurred:
ArgumentError Traceback (most recent call last)
in <module>()
----> 1 c_arr = C.cast(typed_c_arrptr, dtype_ptr_t) # cast to ctypes
/usr/lib/python3.4/ctypes/__init__.py in cast(obj, typ)
486 _cast = PYFUNCTYPE(py_object, c_void_p, py_object, py_object)(_cast_addr)
487 def cast(obj, typ):
--> 488 return _cast(obj, obj, typ)
489
490 _string_at = PYFUNCTYPE(py_object, c_void_p, c_int)(_string_at_addr)
ArgumentError: argument 1: <class 'TypeError'>: wrong type
在代码执行的那个时刻,typed_c_arrptr在程序的两个版本中都是一个dtype(&#39; int64&#39;)。 dtype_ptr_t是LP_c_char_Array_4 同样在两个版本中。
我在typed_c_arrptr = c_arrptr.astype(int)上尝试了很多变种,用ctypes.c_int,ctypes.c_long,ctypes.c_size_t替换int。在这一点上,我只是在猜测做什么和出了什么问题。任何有关这方面的帮助将不胜感激。
答案 0 :(得分:0)
错误告诉您,第一个参数无法转换为ctypes.c_void_p
。那是typed_c_arrptr
无法转换的。
这种情况发生了,因为astype()
在两个版本的Python中的工作方式不同。使用Python 3,你有
>>> isinstance(np.uint64(12345).astype(int), int)
False
因此ctypes不知道如何转换np.uint64
。而使用Python 2你有
>>> isinstance(np.uint64(12345).astype(int), int)
True
因此ctypes只会将其视为int
。
进一步the documentation of generic.astype()
读取
未实施(虚拟属性)
类泛型仅用于派生numpy标量,并且拥有ndarray类的所有属性,尽管未实现,以便提供统一的API。
我不知道为什么它适用于Python 2。
相反,您可以使用int()
将np.uint64
转换为可以转换为ctypes.c_void_p
的内容。这对我来说都适用于两个版本。
c_arr = C.cast(int(c_arrptr), dtype_ptr_t)