ctypes.cast在python2中工作,并在python3中抛出ArgumentError

时间:2015-07-07 15:52:07

标签: python numpy ctypes

我遇到的问题是我的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。在这一点上,我只是在猜测做什么和出了什么问题。任何有关这方面的帮助将不胜感激。

1 个答案:

答案 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)