Eur*_*lho 6 python ctypes numpy
我正在尝试将共享C库与某些python代码连接起来.与库的接口是这样的
typedef struct{
int v1;
double* v2} input;
Run Code Online (Sandbox Code Playgroud)
还有另外两种类型,例如:配置和输出类型.
我在python中使用ctypes Structure如下设置这些结构:
class input(Structure):
_fields_ = [("v1",c_int),("v2",POINTER(c_double)]
Run Code Online (Sandbox Code Playgroud)
C代码有一些函数接收指向该结构的指针,argtypes定义如下:
fun.argtypes = [constraints,input,POINTER(input)]
Run Code Online (Sandbox Code Playgroud)
constraints是另一个具有一些int配置字段的结构.
首先,我更新输入结构中的v2字段
input.v2 = generated_array.ctypes.data_as(POINTER(c_double))
Run Code Online (Sandbox Code Playgroud)
然后我称之为:
fun(constraints,input,byref(output))
Run Code Online (Sandbox Code Playgroud)
函数原型请求struct和*to struct(假设输出结构类型与输入结构类型相同).
然后我想访问存储在输出的v2字段中的乐趣结果.但是我得到了意想不到的结果.这样做有更好/更正确的方法吗?
我在这里搜索了很多并阅读了文档,但我找不到有什么问题.我没有任何错误消息,但是我从共享库中收到的警告似乎表明这些接口存在错误.
我猜我发现了这个问题:
当我调用该方法时,会调用一个numpy数组.然后我创建了4个向量:
out_real = ascontiguousarray(zeros(din.size,dtype=c_double))
out_imag = ascontiguousarray(zeros(din.size,dtype=c_double))
in_real = ascontiguousarray(din.real,dtype = c_double)
in_imag = ascontiguousarray(din.imag,dtype = c_double)
Run Code Online (Sandbox Code Playgroud)
其中din是输入向量.我用这种方式测试了方法:
print in_real.ctypes.data_as(POINTER(c_double))
print in_imag.ctypes.data_as(POINTER(c_double))
print out_real.ctypes.data_as(POINTER(c_double))
print out_imag.ctypes.data_as(POINTER(c_double))
Run Code Online (Sandbox Code Playgroud)
结果是:
<model.LP_c_double object at 0x1d81f80>
<model.LP_c_double object at 0x1d81f80>
<model.LP_c_double object at 0x1d81f80>
<model.LP_c_double object at 0x1d81f80>
Run Code Online (Sandbox Code Playgroud)
似乎所有人都指向同一个地方.
经过一些更改后,它按预期工作...
经过几次测试后,我发现第一次代码几乎是正确的.我创建了一次Structure实例并更新了它的字段.我改为在每次调用时创建一个新实例fun.我还将所有数组类型更改为等效的ctypes类型; 这似乎使功能按预期工作.
打印行为仍然保持在上面的测试中,但即使有这种奇怪的行为,该功能似乎也能正常工作.正如下面的@ericsun评论指出的那样正确.
有struct一个int可能用于数组长度的字段,尽管我只是在没有完整函数原型的情况下猜测。如果确实如此,这里有一个示例可能会有所帮助。
首先,我需要在共享库中编译一个测试函数。我只需将输入数组乘以 2:
import os
import numpy as np
from ctypes import *
open('tmp.c', 'w').write('''\
typedef struct {
int v1; double *v2;
} darray;
int test(darray *input, darray *output) {
int i;
/* note: this should first test for compatible size */
for (i=0; i < input->v1; i++)
*(output->v2 + i) = *(input->v2 + i) * 2;
return 0;
}
''')
os.system('gcc -shared -o tmp.so tmp.c')
Run Code Online (Sandbox Code Playgroud)
接下来创建 ctypes 定义。我添加了 a以从 aclassmethod制作a :darraynumpy.ndarray
c_double_p = POINTER(c_double)
class darray(Structure):
_fields_ = [
('v1', c_int),
('v2', c_double_p),
]
@classmethod
def fromnp(cls, a):
return cls(len(a), a.ctypes.data_as(c_double_p))
lib = CDLL('./tmp.so')
lib.test.argtypes = POINTER(darray), POINTER(darray)
Run Code Online (Sandbox Code Playgroud)
测试:
a1 = np.arange(3) + 1.0
a2 = np.zeros(3)
print 'before:', '\na1 =', a1, '\na2 =', a2
lib.test(darray.fromnp(a1), darray.fromnp(a2))
print 'after:', '\na1 =', a1, '\na2 =', a2
Run Code Online (Sandbox Code Playgroud)
输出:
before:
a1 = [ 1. 2. 3.]
a2 = [ 0. 0. 0.]
after:
a1 = [ 1. 2. 3.]
a2 = [ 2. 4. 6.]
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1901 次 |
| 最近记录: |