在通过ctypes调用的c函数中实例化python对象

2024-04-25 06:47:51 发布

您现在位置:Python中文网/ 问答频道 /正文

当我从ctypes调用的c函数实例化Python对象时,我的嵌入式python3.3程序出现错误。在

设置好解释器后,我可以从c main成功地实例化python Int(以及自定义的c扩展类型):

#import <Python/Python.h>  

#define LOGPY(x) \
{ fprintf(stderr, "%s: ", #x); PyObject_Print((PyObject*)(x), stderr, 0); fputc('\n', stderr); }

// c function to be called from python script via ctypes.
void instantiate() {
  PyObject* instance = PyObject_CallObject((PyObject*)&PyLong_Type, NULL);
  LOGPY(instance);
}

int main(int argc, char* argv[]) {
  Py_Initialize();
  instantiate(); // works fine

  // run a script that calls instantiate() via ctypes.
  FILE* scriptFile = fopen("emb.py", "r");
  if (!scriptFile) {
    fprintf(stderr, "ERROR: cannot open script file\n");
    return 1;
  }

  PyRun_SimpleFileEx(scriptFile, scriptPath, 1); // close on completion
  return 0;
}

然后我使用PyRun_SimpleFileEx运行一个python脚本。它看起来运行得很好,但是当它通过ctypes调用instantiate()时,程序在PyObject_CallObject中出现错误:

^{pr2}$

lldb输出:

instance: 0
Process 52068 stopped
* thread #1: tid = 0x1c03, 0x000000010000d3f5 Python`PyObject_Call + 69, stop reason = EXC_BAD_ACCESS (code=1, address=0x18)
    frame #0: 0x000000010000d3f5 Python`PyObject_Call + 69
Python`PyObject_Call + 69:
-> 0x10000d3f5:  movl   24(%rax), %edx
   0x10000d3f8:  incl   %edx
   0x10000d3fa:  movl   %edx, 24(%rax)
   0x10000d3fd:  leaq   2069148(%rip), %rax       ; _Py_CheckRecursionLimit
(lldb) bt
* thread #1: tid = 0x1c03, 0x000000010000d3f5 Python`PyObject_Call + 69, stop reason = EXC_BAD_ACCESS (code=1, address=0x18)
    frame #0: 0x000000010000d3f5 Python`PyObject_Call + 69
    frame #1: 0x00000001000d5197 Python`PyEval_CallObjectWithKeywords + 87
    frame #2: 0x0000000201100d8e emb`instantiate + 30 at emb.c:9

为什么只从ctypes调用instantiate()失败?这个函数只有在调用python库时才会崩溃,所以可能某些解释器状态被ctypes FFI调用所破坏?在


Tags: 实例instance函数程序stderrscriptcallctypes
1条回答
网友
1楼 · 发布于 2024-04-25 06:47:51

多亏了阿明·里戈的提示。问题是通过ctypes.CDLL()创建在调用本机代码时释放GIL的函数。据我所知,这意味着为了让本机函数调用python代码,它需要首先使用pythoncapi获取GIL。在

更简单的选择是使用ctypes.PyDLL(),它不释放GIL(它还检查python错误标志)。文档说,“因此,这只对直接调用pythoncapi函数有用。”我的代码更间接,因为我有Python代码调用我自己的C函数,然后调用pythoncapi,但问题是一样的。在

相关问题 更多 >