我想出了如何让 Python 从我的共享库调用函数:
import ctypes
def bar():
return 1337
dll = ctypes.PyDLL("./mod.so")
assert dll.foo(ctypes.c_float(42)) == 42 + 1337
其中
mod.so
可以像 C:中那样调用
bar
Python 函数
int foo(float f) {
PyObject *module = PyImport_ImportModule("main");
PyObject *bar = PyObject_GetAttrString(module, "bar");
PyObject *args = PyTuple_Pack(0);
PyObject *result = PyObject_CallObject(bar, args);
return f + PyLong_AsInt(result);
}
我本质上是在寻找一种方法让 C
foo()
函数直接调用 Python 代码中的函数,而不需要像 PyObject_CallObject()
这样的 Python 特定内容。这就是我试图将 C 文件变成:
int foo(float f) {
return f + bar();
}
这很好,但是我的编程语言(参见我的博客文章)其编译器+链接器输出一个通用的
mod.so
,应该可以由任何编程语言使用,所以不仅仅是Python。
这个
mod.so
对于 C 和 C++ 来说是开箱即用的,因为共享库只是使用 call
指令来调用主可执行文件的 bar
函数。另一方面,Python(以及大多数其他高级语言)不允许您直接调用这样的 Python 函数。这是有道理的,因为 Python 将原始 C 类型包装在自定义结构中。这就是为什么我们需要在上面的代码中调用 PyObject_CallObject()
。
我可以编写一个程序,用
call
+ PyImport_ImportModule()
+ 等调用链替换所有 PyObject_GetAttrString()
指令,但出于技术原因,我更愿意单独保留 mod.so
。
我所做的工作是在 Python 代码和
adapter.c
之间放置一个 mod.so
作为中间人。 adapter.so
的存在只是为了公开 bar
可以直接调用的 mod.so
包装函数,其中包含 PyObject_CallObject
和 co。来电。有关粗略代码,请参阅我之前的 Stack Overflow 问题。
因为我的编程语言已经要求游戏开发者在
mod_api.json
中记录mod API,所以可以自动重新生成这个adapter.c
文件,但理想情况下根本不需要这一步。
Python 是否允许定义共享库可以直接调用的 C 函数?如果是这样,那么我就不必担心修改
mod.so
或拥有 adapter.c
。谢谢。
我输入了此内容,然后向上滚动,发现您可能已经回答了自己的问题。 我能够从 docs.python.org 上的 Python 文档中检索“ctypes”(Python 的外部函数库)的此信息。 它基本上允许您调用 dll 或共享库中的函数。 源代码位于 docs.python.org/3/library/ctypes 的 Lib/ctypes。