
快速修复 (有关详细信息和更复杂的方法,请继续阅读):
您需要
PyArray_API通过调用
import_array()以下命令在使用numpy-stuff的每个cpp文件中初始化变量:
//it is only a trick to ensure import_array() is called, when *.so is loaded//just called only onceint init_numpy(){ import_array(); // PyError if not successful return 0;}const static int numpy_initialized = init_numpy();void parse_ndarraray(PyObject *obj) { // would be called every time if (PyArray_Check(obj)) { cout << "PyArray_Check Passed" << endl; } else { cout << "PyArray_Check Failed" << endl; }}也可以使用
_import_array,如果失败则返回负数,以使用自定义错误处理。有关的定义,请参见此处
import_array。
警告: 正如@
isra60所指出的,
_import_array()/import_array()只有在初始化Python之后(即在
Py_Initialize()调用之后)才能调用。扩展总是如此,但如果嵌入了python解释器,则并非总是如此,因为它
numpy_initialized是在
main-starts之前初始化的。在这种情况下,不应使用“初始化技巧”,而应
init_numpy()在之后调用
Py_Initialize()。
精密的解决方案:
NB:有关信息,为什么
PyArray_API需要设置,请参见以下SO-
answer:为了能够将符号解析推迟到运行时,因此在链接时不需要numpy的共享库,并且不能将其放在dynamic-library-路径(那么python的系统路径就足够了)。
提出的解决方案是快速的,但是如果使用numpy的cpp有多个,则其中一个会初始化很多PyArray_API实例。
如果
PyArray_API不是将其定义为静态的,而是将其定义为
extern一个翻译单元,则可以避免这种情况。对于那些翻译单元,
NO_import_ARRAY必须先定义宏,然后
numpy/arrayobject.h再包含宏。
但是,我们需要一个定义该符号的翻译单元。对于此翻译单元,
NO_import_ARRAY不得定义宏。
但是,如果不定义宏,
PY_ARRAY_UNIQUE_SYMBOL我们将仅获得一个静态符号,即对于其他翻译单元不可见,因此链接器将失败。这样做的原因是:如果有两个库,每个人都定义一个a,
PyArray_API那么我们将对符号进行多重定义,并且链接器将失败,即,我们无法将这两个库一起使用。
因此,通过定义
PY_ARRAY_UNIQUE_SYMBOL为
MY_FANCY_LIB_PyArray_API每之前包括
numpy/arrayobject.h我们有我们自己的
PyArray_API-name,这不会与其他库发生冲突。
放在一起:
答: use_numpy.h-您包含numpy功能的标题,即
numpy/arrayobject.h
//use_numpy.h//your fancy name for the dedicated PyArray_API-symbol#define PY_ARRAY_UNIQUE_SYMBOL MY_PyArray_API//this macro must be defined for the translation unit #ifndef INIT_NUMPY_ARRAY_CPP #define NO_import_ARRAY //for usual translation units#endif//now, everything is setup, just include the numpy-arrays:#include <numpy/arrayobject.h>
B:
init_numpy_api.cpp-用于初始化global的翻译单元
MY_PyArray_API:
//init_numpy_api.cpp//first make clear, here we initialize the MY_PyArray_API#define INIT_NUMPY_ARRAY_CPP//now include the arrayobject.h, which defines//void **MyPyArray_API#inlcude "use_numpy.h"//now the old trick with initialization:int init_numpy(){ import_array();// PyError if not successful return 0;}const static int numpy_initialized = init_numpy();C:
use_numpy.h只要需要时就包含numpy,它将定义
extern void **MyPyArray_API:
//example#include "use_numpy.h"...PyArray_Check(obj); // works, no segmentation error
警告: 不应忘记,
Py_Initialize()必须已经调用了初始化技巧才能起作用。
为什么需要它 (出于历史原因保留):
当我用调试符号构建扩展名时:
extra_compile_args=['-fPIC', '-O0', '-g'],extra_link_args=['-O0', '-g'],
并使用gdb运行它:
gdb --args python run_test.py (gdb) run --- Segmentation fault (gdb) disass
我可以看到以下内容:
0x00007ffff1d2a6d9 <+20>: mov 0x203260(%rip),%rax # 0x7ffff1f2d940 <_ZL11PyArray_API> 0x00007ffff1d2a6e0 <+27>: addPyArray_Checkx10,%rax=> 0x00007ffff1d2a6e4 <+31>: mov (%rax),%rax ... (gdb) print $rax = 16
我们应该记住,这
#define PyArray_Check(op) PyObject_TypeCheck(op, &PyArray_Type)仅是针对以下方面的定义:
&PyArray_Type
看来,这
PyArray_API使用了某种方式
0未初始化的一部分 (具有value
cpp_parser.cpp)。
让我们看一下
-E预处理器之后(与flag一起编译
static void **PyArray_API= __null ... static int_import_array(void){ PyArray_API = (void **)PyCapsule_GetPointer(c_api,...:PyArray_AP
所以
_import_array(void)我是静态的,并且通过初始化
_import_array(),实际上可以解释我在构建期间收到的警告,该警告
PyArray_API已定义但未使用-
我们未初始化
PyArray_API。
因为
import_array()是静态变量,所以必须在每个编译单元(即cpp-文件)中对其进行初始化。
因此,我们只需要这样做-似乎是官方方式。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)