将 swig python 'double *' 对象读入 numpy(也许通过 ctypes?)
Read swig python 'double *' object into numpy (maybe through ctypes?)
我有无法修改的 swig python 库。
它 returns 一个 <Swig object of type 'double *'>
我知道它是一个指向双精度数组的指针。通过一个单独的函数,我得到了一个 python int 作为长度。
我的问题是,如何将这些数据读入 numpy?
我找到了 numpy.ndarray.ctypes 模块,另一个 Whosebug 答案暗示可以从 SWIG 转换为 ctypes (),但没有提及如何转换。
感谢任何帮助。
我创建了一个示例 SWIG 包装器来测试它:
%module test
%{
#include <stdlib.h>
#include <stdio.h>
double* get(void)
{
double* p = malloc(sizeof(double) * 10);
for(int i = 0; i < 10; ++i)
p[i] = 1.1 * i;
printf("%p\n",p);
return p;
}
%}
double* get(void);
以下通过ctypes检索数据:
>>> import test
>>> a = test.get()
000001A3D05ED890 # From the printf...
>>> a
<Swig Object of type 'double *' at 0x000001A3D27D6030>
>>> hex(int(a))
'0x1a3d05ed890' # int() of the object is the same address
>>> from ctypes import *
>>> p = (c_double * 10).from_address(int(a))
>>> list(p)
[0.0, 1.1, 2.2, 3.3000000000000003, 4.4, 5.5, 6.6000000000000005, 7.700000000000001, 8.8, 9.9]
现在是 numpy。可能有更好的方法,但我发现 __array_interface__
(link)。 "array-like" 对象具有此接口,可以从中创建另一个数组:
>>> class Tmp: pass
...
>>> Tmp.__array_interface__ = {'shape':(10,),'typestr':'<f8','data':(int(a),False),'version':3}
>>> import numpy as np
>>> np.array(Tmp,copy=False) # Create array that shares the same interface
array([0. , 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9])
也许不是最好的方法,但我不是 numpy 的重度用户。
如果您想从 C 接收数组,我建议您使用 NumPy SWIG 绑定 numpy.i
。
我在这里使用 ARGOUTVIEWM_ARRAY1
这样在 C 中分配的内存从此以后将由 NumPy 数组管理。如果这不符合您的需要,您可以选择不同的类型映射。有good documentation.
我还重命名了 library_function
,这样我就可以用我自己的函数覆盖它,该函数具有正确的 NumPy 类型映射签名。
test.t
%module example
%{
#define SWIG_FILE_WITH_INIT
#include <stdlib.h>
#include <stdio.h>
double* library_function(void)
{
double* p = malloc(sizeof(double) * 10);
for(int i = 0; i < 10; ++i)
p[i] = 1.1 * i;
printf("%p\n",p);
return p;
}
%}
%include "numpy.i"
%init %{
import_array();
%}
%apply (double** ARGOUTVIEWM_ARRAY1, int* DIM1) {(double** data, int* length)};
%rename (library_function) encapsulate_library_function;
%inline %{
void encapsulate_library_function(double** data, int* length) {
*data = library_function();
*length = 10;
}
%}
test.py
from example import library_function
a = library_function()
print(type(a))
print(a)
调用示例:
$ swig -python test.i
$ clang -Wall -Wextra -Wpedantic -I /usr/include/python3.6m/ -fPIC -shared -o _example.so test_wrap.c -lpython3.6m
$ python3 test.py
0x2b9d4a0
<class 'numpy.ndarray'>
[ 0. 1.1 2.2 3.3 4.4 5.5 6.6 7.7 8.8 9.9]
我有无法修改的 swig python 库。
它 returns 一个 <Swig object of type 'double *'>
我知道它是一个指向双精度数组的指针。通过一个单独的函数,我得到了一个 python int 作为长度。
我的问题是,如何将这些数据读入 numpy?
我找到了 numpy.ndarray.ctypes 模块,另一个 Whosebug 答案暗示可以从 SWIG 转换为 ctypes (
感谢任何帮助。
我创建了一个示例 SWIG 包装器来测试它:
%module test
%{
#include <stdlib.h>
#include <stdio.h>
double* get(void)
{
double* p = malloc(sizeof(double) * 10);
for(int i = 0; i < 10; ++i)
p[i] = 1.1 * i;
printf("%p\n",p);
return p;
}
%}
double* get(void);
以下通过ctypes检索数据:
>>> import test
>>> a = test.get()
000001A3D05ED890 # From the printf...
>>> a
<Swig Object of type 'double *' at 0x000001A3D27D6030>
>>> hex(int(a))
'0x1a3d05ed890' # int() of the object is the same address
>>> from ctypes import *
>>> p = (c_double * 10).from_address(int(a))
>>> list(p)
[0.0, 1.1, 2.2, 3.3000000000000003, 4.4, 5.5, 6.6000000000000005, 7.700000000000001, 8.8, 9.9]
现在是 numpy。可能有更好的方法,但我发现 __array_interface__
(link)。 "array-like" 对象具有此接口,可以从中创建另一个数组:
>>> class Tmp: pass
...
>>> Tmp.__array_interface__ = {'shape':(10,),'typestr':'<f8','data':(int(a),False),'version':3}
>>> import numpy as np
>>> np.array(Tmp,copy=False) # Create array that shares the same interface
array([0. , 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9])
也许不是最好的方法,但我不是 numpy 的重度用户。
如果您想从 C 接收数组,我建议您使用 NumPy SWIG 绑定 numpy.i
。
我在这里使用 ARGOUTVIEWM_ARRAY1
这样在 C 中分配的内存从此以后将由 NumPy 数组管理。如果这不符合您的需要,您可以选择不同的类型映射。有good documentation.
我还重命名了 library_function
,这样我就可以用我自己的函数覆盖它,该函数具有正确的 NumPy 类型映射签名。
test.t
%module example
%{
#define SWIG_FILE_WITH_INIT
#include <stdlib.h>
#include <stdio.h>
double* library_function(void)
{
double* p = malloc(sizeof(double) * 10);
for(int i = 0; i < 10; ++i)
p[i] = 1.1 * i;
printf("%p\n",p);
return p;
}
%}
%include "numpy.i"
%init %{
import_array();
%}
%apply (double** ARGOUTVIEWM_ARRAY1, int* DIM1) {(double** data, int* length)};
%rename (library_function) encapsulate_library_function;
%inline %{
void encapsulate_library_function(double** data, int* length) {
*data = library_function();
*length = 10;
}
%}
test.py
from example import library_function
a = library_function()
print(type(a))
print(a)
调用示例:
$ swig -python test.i
$ clang -Wall -Wextra -Wpedantic -I /usr/include/python3.6m/ -fPIC -shared -o _example.so test_wrap.c -lpython3.6m
$ python3 test.py
0x2b9d4a0
<class 'numpy.ndarray'>
[ 0. 1.1 2.2 3.3 4.4 5.5 6.6 7.7 8.8 9.9]