如何用C/C++实现支持持续会话的交互式Python控制台?
交互式Python Shell的C语言实现示例
要实现持续会话的交互式Python调用,你可以使用PyRun_InteractiveLoop函数(复用Python原生交互逻辑),或者手动循环处理输入、执行代码并捕获输出。以下是两种实用实现方式:
方式一:基于PyRun_InteractiveLoop快速实现
这个方法直接复用Python内置的交互循环,代码简洁,体验和原生Python shell一致:
#define PY_SSIZE_T_CLEAN #include <Python.h> #include <stdio.h> int main(int argc, char *argv[]) { wchar_t *program = Py_DecodeLocale(argv[0], NULL); if (program == NULL) { fprintf(stderr, "Fatal error: cannot decode argv[0]\n"); exit(1); } Py_SetProgramName(program); Py_Initialize(); // 从标准输入读取指令,持续执行直到退出 PyRun_InteractiveLoop(stdin, "<stdin>"); if (Py_FinalizeEx() < 0) { exit(120); } PyMem_RawFree(program); return 0; }
说明
PyRun_InteractiveLoop会自动处理多行输入、提示符(>>>/...)、异常提示等逻辑,用户输入exit()或按下Ctrl+D即可退出会话。
方式二:手动控制输入输出(自定义交互逻辑)
如果需要自定义输入读取、输出存储或会话规则,可以手动循环执行代码,结合输出重定向实现:
#define PY_SSIZE_T_CLEAN #include <Python.h> #include <stdio.h> #include <string.h> // 重定向Python输出的回调函数 static int redirect_output(PyObject *self, PyObject *args) { const char *output; if (!PyArg_ParseTuple(args, "s", &output)) { return 0; } // 此处可将输出写入自定义缓冲区,示例直接打印到终端 printf("%s", output); return 0; } static PyMethodDef RedirectMethods[] = { {"write", redirect_output, METH_VARARGS, "Redirect Python output"}, {NULL, NULL, 0, NULL} }; static struct PyModuleDef redirectmodule = { PyModuleDef_HEAD_INIT, "redirect", NULL, -1, RedirectMethods }; PyMODINIT_FUNC PyInit_redirect(void) { return PyModule_Create(&redirectmodule); } int main(int argc, char *argv[]) { wchar_t *program = Py_DecodeLocale(argv[0], NULL); if (program == NULL) { fprintf(stderr, "Fatal error: cannot decode argv[0]\n"); exit(1); } Py_SetProgramName(program); Py_Initialize(); // 替换sys.stdout,捕获Python输出 PyObject *sys_module = PyImport_ImportModule("sys"); PyObject *redirect_module = PyImport_ImportModule("redirect"); PyObject *redirect_write = PyObject_GetAttrString(redirect_module, "write"); PyObject_SetAttrString(sys_module, "stdout", redirect_write); // 释放临时引用 Py_XDECREF(sys_module); Py_XDECREF(redirect_module); Py_XDECREF(redirect_write); char input_buf[1024]; printf(">>> "); while (fgets(input_buf, sizeof(input_buf), stdin) != NULL) { // 去除换行符 input_buf[strcspn(input_buf, "\n")] = '\0'; if (strcmp(input_buf, "exit") == 0) { break; } // 执行输入的Python代码 PyObject *main_module = PyImport_AddModule("__main__"); PyObject *global_dict = PyModule_GetDict(main_module); PyObject *result = PyRun_String(input_buf, Py_single_input, global_dict, global_dict); if (result == NULL) { // 打印异常信息 PyErr_Print(); } else { // 输出执行结果 PyObject *repr = PyObject_Repr(result); char *result_str = PyUnicode_AsUTF8(repr); printf("%s\n", result_str); // 释放引用 Py_XDECREF(repr); Py_XDECREF(result); } printf(">>> "); } if (Py_FinalizeEx() < 0) { exit(120); } PyMem_RawFree(program); return 0; }
说明
- 输出重定向:通过自定义Python模块替换
sys.stdout.write,可以将Python的输出捕获到自定义缓冲区或其他存储位置。 - 会话控制:手动读取用户输入,支持自定义退出指令(示例中为
exit),灵活控制会话生命周期。 - 结果处理:捕获代码执行结果,将其转为字符串输出;若执行出错,自动打印异常信息。
编译注意事项
Linux下编译需链接Python库:
gcc -o python_interactive python_interactive.c $(python3-config --cflags --ldflags)
Windows下需配置Python的包含目录和库目录,链接对应版本的pythonXY.lib(XY为Python版本号,如python311.lib)。
内容的提问来源于stack exchange,提问作者user19095524
相关产品推荐
相关产品推荐

