如何使用ctypes将null传递给外部库,并使用ctypeslib.ndpointer声明参数?

时间:2015-08-20 13:53:09

标签: python python-2.7 numpy ctypes

受到另一个answer的启发,我有一个ctypes函数,我使用ctypeslib.ndpointer调用:

lib.foo.argtypes = [ctypeslib.ndpointer(np.complex64, ndim=1, flags='C'), POINTER(c_int)]

外部函数声明如下:

void foo(cmplx_float *array, int *length)

我的问题是我想要两次调用该函数。我第一次想将nullptr传递给array参数,以便找出所需的长度。然后第二次,我将传递一个numpy数组。

所以我这样做:

lib.foo(None, length)

此操作失败,并显示以下错误:

  

ctypes.ArgumentError:参数1 ::参数必须是ndarray

我可以通过nullptr吗?

2 个答案:

答案 0 :(得分:4)

如果(像我一样)你正在处理多种不同的数组类型,一个稍微好一点的解决方法是自己包装ndpointer

import numpy as np
from numpy.ctypeslib import ndpointer

def wrapped_ndptr(*args, **kwargs):
  base = ndpointer(*args, **kwargs)
  def from_param(cls, obj):
    if obj is None:
      return obj
    return base.from_param(obj)
  return type(base.__name__, (base,), {'from_param': classmethod(from_param)})

ComplexArrayType = wrapped_ndptr(dtype=np.complex128, ndim=1, flags='C_CONTIGUOUS')
DoubleArrayType = wrapped_ndptr(dtype=np.float64, ndim=1, flags='C_CONTIGUOUS')

答案 1 :(得分:1)

根据eryksun在评论中的出色建议,我将ctypeslib.ndpointer返回的类型子类化,并实现了重写from_param。这有点棘手,因为它必须使用类工厂技术来完成,因为ctypeslib.ndpointer返回的类是由工厂生成的。

我最终得到的代码:

_ComplexArrayTypeBase = numpy.ctypeslib.ndpointer(dtype=numpy.complex128, ndim=1,
    flags='C_CONTIGUOUS')

def _from_param(cls, obj):
    if obj is None:
        return obj
    return _ComplexArrayTypeBase.from_param(obj)

ComplexArrayType = type(
    'ComplexArrayType',
    (_ComplexArrayTypeBase,),
    {'from_param': classmethod(_from_param)}
)

非常感谢eryksun(一如既往)专家建议。