在ctypes结构中访问np.array

jrs*_*rsm 4 python ctypes numpy

我有一个动态分配数组的ctypes结构,即:

array_1d_double=npct.ndpointer(dtype=np.double,ndim=1,
                               flags='CONTIGUOUS')
class Test(Structure):
    _fields_ = ("x", array_1d_double, ..)

test = Test()
do_some_init_in_c(  for example malloc)
Run Code Online (Sandbox Code Playgroud)

如果我打印test.x,我得到以下输出:

<ndpointer_<f8_1d_CONTIGUOUS object at 0x7f104dc0c3b0>
Run Code Online (Sandbox Code Playgroud)

c结构看起来大致如此,

structure Test_s{
    double *x;....
};
Run Code Online (Sandbox Code Playgroud)

如何像numpy数组一样访问这个元素?是否可能需要将数组分配为np.arrays而不是使用malloc?这样做的正确方法是什么?

eba*_*arr 6

做你正在谈论的一种方法是直接在python端分配numpy数组,并且表现得像是C端的直接双数组.

import numpy as np
import ctypes as C

# allocate this as a normal numpy array with specified dtype
array_1d_double = np.array([1,2,3,4,5],dtype="float64")

# set the structure to contain a C double pointer
class Test(C.Structure):
    _fields_ = [("x", C.POINTER(C.c_double))]

# Instantiate the structure so it can be passed to the C code
test = Test(np.ctypeslib.as_ctypes(array_1d_double))

# You can also do:
# test = Test()
# test.x = np.ctypeslib.as_ctypes(array_1d_double)

print test.x
# outputs: <__main__.LP_c_double object at 0x1014aa320>
Run Code Online (Sandbox Code Playgroud)

您现在应该能够将结构的x成员用作C代码中的普通双数组.

编辑:

澄清一下:如果实例化Structure没有参数的a,它会NULL为其所有成员提供指针.

class Test(C.Structure):
    _fields_ = [("x", C.POINTER(C.c_double)),
                ("y", C.POINTER(C.c_int))]

test = Test()
print test.x
# outputs: <__main__.LP_c_double object at 0x1014aa320>

print test.y
# outputs: <__main__.LP_c_int object at 0x101429320>

print test.x[0]
# raises ValueError: NULL pointer access

print test.y[0]
# raises ValueError: NULL pointer access
Run Code Online (Sandbox Code Playgroud)

如果使用N个参数实例化Structure,那么这些参数将分配给Structure的前N个成员.

test = Test(np.ctypeslib.as_ctypes(array_1d_double))

print text.x[0]
# outputs: 1.0

print test.y[0]
# raises ValueError: NULL pointer access
Run Code Online (Sandbox Code Playgroud)

EDIT2

如果要将numpy数组永久绑定到结构,可以覆盖该__init__方法:

class MyDualArrayStruct(C.Structure):
    _fields_ = [("c_x", C.POINTER(C.c_double)),
                ("c_y", C.POINTER(C.c_int))]

    def __init__(self,*args,**kwargs):
        super(MyDualArrayStruct,self).__init__(*args,**kwargs)
        self.np_x = np.array([1,2,3,4,5],dtype="float64")
        self.c_x = np.ctypeslib.as_ctypes(self.np_x)
        self.np_y = np.array([5,4,3,2,1],dtype="int32")
        self.c_y = np.ctypeslib.as_ctypes(self.np_y)

test = MyDualArrayStruct()

print test.np_x
print test.c_x[:5]

# Note that here c_x and np_x both contain the same data. Thus modifying one of them
# (inplace) modifies the other. You can use this to do easy inplace modification of 
# numpy arrays in C functions.
# This implies that test.np_x.sum() is also the sum of test.c_x
test.np_x[:] = 1

print test.np_x
print test.c_x[:5]
Run Code Online (Sandbox Code Playgroud)

这输出:

[ 1.  2.  3.  4.  5.]
[1.0, 2.0, 3.0, 4.0, 5.0]
[ 1.  1.  1.  1.  1.]
[1.0, 1.0, 1.0, 1.0, 1.0]
Run Code Online (Sandbox Code Playgroud)