去年,需要用 Python3中的功能来补充用C编写的旧项目。 尽管事实上有关于此主题的文章,但我在当年和现在写这篇文章的程序时都受了苦。 因此,我将给出一些示例,说明如何在Linux下使用C使用Python3(使用我的用法)。 我将描述如何创建一个类并调用其方法来访问变量。 调用函数并从模块获取变量。 还有我遇到的无法理解的问题。
配套
我们使用标准的Python API forC。 所需的Python软件包:
- python3
- python3-dev
- python3-all
- python3-all-dev
- libpython3-all-dev
在口译员中工作
最简单的事情是在Python解释器中加载和工作。
要工作,必须连接头文件:
#include <Python.h>
加载解释器:
Py_Initialize();
接下来是Python的一部分工作,例如:
PyRun_SimpleString("print('Hello!')");
卸载解释器:
Py_Finalize();
完整示例:
#include <Python.h> void main() { // Python Py_Initialize(); // PyRun_SimpleString("print('Hello!')"); // Python Py_Finalize(); }
如何编译和运行:
gcc simple.c $(python3-config --includes --ldflags) -o simple && ./simple Hello!
但这不起作用:
gcc $(python3-config --includes --ldflags) simple.c -o simple && ./simple /tmp/ccUkmq57.o: In function `main': simple.c:(.text+0x5): undefined reference to `Py_Initialize' simple.c:(.text+0x16): undefined reference to `PyRun_SimpleStringFlags' simple.c:(.text+0x1b): undefined reference to `Py_Finalize' collect2: error: ld returned 1 exit status
这是因为python3-config --includes --ldflags扩展为这种类型的东西:
-I/usr/include/python3.6m -I/usr/include/python3.6m -L/usr/lib/python3.6/config-3.6m-x86_64-linux-gnu -L/usr/lib -lpython3.6m -lpthread -ldl -lutil -lm -Xlinker -export-dynamic -Wl,-O1 -Wl,-Bsymbolic-functions
在这里,我认为-Wl链接器的连接顺序很重要 。 谁能更确切地知道,在评论中写些,我将补充答案。
MooNDeaR的 解释 :
一切都非常简单-一次搜索字符,所有未使用的字符都将被丢弃。 如果将simple.c放在最后,结果表明链接器在查看python库后将看到Py_Initialize()符号的使用,此刻所有符号都将被丢弃(因为未使用它们)。
从Python文件调用函数的示例:
简单的
#include <Python.h> void python() { // Python Py_Initialize(); // // sys PyRun_SimpleString("import sys"); // python PyRun_SimpleString("sys.path.append('./src/python')"); PyRun_SimpleString("import simple"); PyRun_SimpleString("print(simple.get_value(2))"); PyRun_SimpleString("print(simple.get_value(2.0))"); PyRun_SimpleString("print(simple.get_value(\"Hello!\"))"); // Python Py_Finalize(); } void main() { puts("Test simple:"); python(); }
simple.py
但是这些都是简单而有趣的事情,我们无法获得函数的结果。
使用函数和模块变量
这有点棘手。
将Python解释器和func.py模块加载到其中:
PyObject * python_init() {
释放Python解释器资源:
void python_clear() {
使用变量和模块功能。
char * python_func_get_str(char *val) { char *ret = NULL;
让我们更详细地讨论这一点。
pVal = PyObject_CallFunction(pObjct, (char *) "(s)", val);
“(s)”表示将1个char *参数作为参数传递给get_value(x) 。 如果我们需要将几个参数传递给该函数,则将如下所示:
pVal = PyObject_CallFunction(pObjct, (char *) "(sss)", val1, val2, val3);
如果您需要传递int ,则将使用字母i ,所有可能的数据类型及其名称都可以在Python 文档中找到。
pVal = PyObject_CallFunction(pObjct, (char *) "(i)", my_int);
func.py:
( 问题已解决 )
我遇到且无法理解的问题:
int main() { puts("Test func:"); if (!python_init()) { puts("python_init error"); return -1; } puts("Strings:"); printf("\tString: %s\n", python_func_get_str("Hello from Python!")); puts("Attrs:"); printf("\ta: %d\n", python_func_get_val("a")); printf("\tb: %d\n", python_func_get_val("b")); printf("\tc: %d\n", python_func_get_val("c")); python_clear(); return 0; }
如果我想从func.py获取b或c ,则打开:
Py_Finalize();
我遇到了细分错误 。 仅获得一个,就没有这种问题。
接收类变量时,也没有问题。
pwl的 解释 :
PyObject PyDict_GetItemString(PyObject p,const char *键)
返回值:借用的参考。 无需做任何借用的参考。
问题是我在为PyDict_GetItemString()调用Py_XDECREF() 。 无需为此功能执行此操作,从而导致分段错误 。
班级工作
仍然有些复杂。
将Python解释器和class.py模块加载到其中。
PyObject * python_init() {
传递字符串作为参数并返回字符串
char * python_class_get_str(char *val) { char *ret = NULL; pVal = PyObject_CallMethod(pInstance, (char *) "get_value", (char *) "(s)", val); if (pVal != NULL) { PyObject* pResultRepr = PyObject_Repr(pVal);
这里没有问题,一切正常,没有错误。 源代码中有一些示例如何使用int , double , bool 。
在编写材料时,我刷新了学识)
我希望它会有用。
参考文献