You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

将Python嵌入C:无法从Python模块导入指定方法的问题

嘿,我来帮你搞定这个问题!你的代码里藏着几个关键问题,导致你遇到找不到方法和段错误的麻烦,咱们一步步捋清楚:

核心问题分析与解决

1. 错误处理完全用错了工具

你用perror来打印Python相关的错误是完全不对的!perror是用来处理系统调用错误的,它只认errno这个系统错误码,但Python的错误是靠自己的异常机制管理的,和errno八竿子打不着。你看到的Can't find method: Success就是因为此时系统根本没出错(errno是0),所以perror瞎输出了个Success,直接把真正的Python错误给掩盖了。

以后只要Python API函数返回NULL,就马上调用PyErr_Print(),这才能看到真正的错误原因,比如模块导入时的语法错误、方法名拼写错了之类的。

2. Python函数没返回值,但C代码硬要解析返回值

你的test.py里myfun()只做了计算和打印,根本没写return语句,所以它默认返回None。但你在C里用PyArg_Parse(ret, "&d", pValue)试图把None解析成double,这不仅会触发Python异常,而且pValue是个没初始化的野指针,直接就导致段错误了。

3. 还有俩小bug要改

  • printf里的格式字符串写错了,你写的"&d"应该是"%d"(如果是整数)或者"%f"(浮点数)
  • pValue没初始化就用,这是典型的未定义行为,绝对不能这么干
修正后的代码

先把test.py改了,给myfun加上返回值:

def myfun():
    c = 123 + 123
    print('the result is: ', c)
    return c  # 必须加这个,不然返回None

# 要是不想模块一导入就自动执行myfun,可以把下面这行注释掉
# myfun()

然后是修正后的main.c,我还加了对象引用计数的管理(Python API里必须手动管理对象内存):

#include <stdio.h>
#include <python3.6/Python.h>

int main() {
    PyObject *pModule, *pMethod, *ret;
    double result;  // 用普通变量存结果,别用野指针

    // 初始化Python解释器,先检查是否成功
    if (!Py_Initialize()) {
        fprintf(stderr, "Python初始化失败\n");
        return 1;
    }

    // 获取sys.path,把当前目录加进去,确保能找到test.py
    PyObject *sys = PyImport_ImportModule("sys");
    if (!sys) {
        PyErr_Print();
        Py_Finalize();
        return 1;
    }
    PyObject *path = PyObject_GetAttrString(sys, "path");
    if (!path) {
        PyErr_Print();
        Py_DECREF(sys);
        Py_Finalize();
        return 1;
    }
    if (PyList_Append(path, PyUnicode_FromString(".")) == -1) {
        PyErr_Print();
        Py_DECREF(path);
        Py_DECREF(sys);
        Py_Finalize();
        return 1;
    }
    // 用完的对象要记得释放,避免内存泄漏
    Py_DECREF(path);
    Py_DECREF(sys);

    // 导入test模块
    pModule = PyImport_ImportModule("test");
    if (!pModule) {
        PyErr_Print();
        Py_Finalize();
        return 1;
    }

    // 获取myfun方法
    pMethod = PyObject_GetAttrString(pModule, "myfun");
    if (!pMethod) {
        PyErr_Print();
        Py_DECREF(pModule);
        Py_Finalize();
        return 1;
    }

    // 额外加个检查:确保拿到的是可调用对象(比如函数)
    if (!PyCallable_Check(pMethod)) {
        fprintf(stderr, "myfun不是可调用对象\n");
        Py_DECREF(pMethod);
        Py_DECREF(pModule);
        Py_Finalize();
        return 1;
    }

    // 调用方法,无参数
    ret = PyEval_CallObject(pMethod, NULL);
    if (!ret) {
        PyErr_Print();
        Py_DECREF(pMethod);
        Py_DECREF(pModule);
        Py_Finalize();
        return 1;
    }

    // 解析返回值为double类型
    if (!PyArg_Parse(ret, "d", &result)) {
        PyErr_Print();
        Py_DECREF(ret);
        Py_DECREF(pMethod);
        Py_DECREF(pModule);
        Py_Finalize();
        return 1;
    }

    // 打印结果
    printf("myfun返回的结果是:%.0f\n", result);

    // 释放所有Python对象
    Py_DECREF(ret);
    Py_DECREF(pMethod);
    Py_DECREF(pModule);

    // 关闭Python解释器
    Py_Finalize();
    return 0;
}
编译和运行注意事项

编译的时候要确保链接正确的Python库,用下面的命令(根据你的Python版本调整):

gcc main.c -o main $(python3.6-config --cflags --ldflags)

然后把test.py和编译出来的main放在同一个目录下,运行./main就可以看到正确结果了。

为什么之前找不到myfun?

等你用了正确的错误处理(PyErr_Print()),就能看到真正的错误信息了。常见的原因包括:

  • test.py不在当前目录,或者sys.path没包含它的路径(不过你已经加了当前目录,这个可能性不大)
  • test.py里有语法错误,导致模块看似导入成功但实际有异常
  • 方法名拼写错了(Python是大小写敏感的,比如MyFun和myfun是俩东西)

内容的提问来源于stack exchange,提问作者Saeley

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 08:48:38