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

C++嵌入Python时如何不执行脚本直接调用Python函数

问题原因

你遇到的两次输出问题由两个原因共同导致:

  1. Python模块加载的固有机制:首次导入模块时,解释器会从头到尾执行模块顶层的所有代码,类、函数的定义本质也是可执行语句,必须运行后才能注册到模块命名空间供外部调用,不存在完全不运行脚本就能导入模块内函数/类的可能。你在foo.py顶层写的foo().test()会在导入时自动执行,输出第一次foo.test。
  2. C++侧调用逻辑错误:test是foo类的实例方法,并不是模块级别的独立函数,你原代码直接从模块对象取test属性本身就不符合Python的对象模型,正常情况下这里会拿到空指针触发调用失败。
正确实现方法

第一步:修改Python脚本,隔离导入时执行和直接运行时执行的逻辑

遵循Python通用编码规范,将不需要在导入时执行的业务入口代码放到if __name__ == "__main__":判断块中——当脚本被直接运行时,模块的__name__属性为"__main__",块内代码会执行;当脚本被导入时,__name__为模块名(这里是"foo"),块内代码不会触发。
修正后的foo.py代码:

# foo.py
class foo:
    def test(self):
        print("foo.test")


if __name__ == "__main__":
    # 仅直接运行脚本时执行,导入时不触发
    foo().test()

第二步:修正C++侧调用逻辑

嵌入式Python调用必须先初始化解释器,按照「获取模块->获取类->实例化类->获取实例方法->调用方法」的层级调用,同时做好引用计数回收和对象合法性校验,避免内存泄漏和崩溃。
修正后的main.cpp代码:

// main.cpp
#include <Python.h>

int main()
{
    // 初始化Python解释器,嵌入式调用必须先执行该步骤
    Py_Initialize();
    // 可选:将当前工作目录加入Python模块搜索路径,避免找不到foo.py
    PyRun_SimpleString("import sys; sys.path.insert(0, '.')");

    PyObject* myModule = PyImport_ImportModule("foo");
    if (myModule)
    {
        // 从模块中获取foo类对象
        PyObject* fooCls = PyObject_GetAttrString(myModule, "foo");
        if (fooCls && PyCallable_Check(fooCls))
        {
            // 实例化foo类
            PyObject* fooInstance = PyObject_CallObject(fooCls, nullptr);
            if (fooInstance)
            {
                // 从实例中获取test方法
                PyObject* testMethod = PyObject_GetAttrString(fooInstance, "test");
                if (testMethod && PyCallable_Check(testMethod))
                {
                    // 调用无参的test方法
                    PyObject_CallObject(testMethod, nullptr);
                    // 释放Python对象引用,避免内存泄漏
                    Py_DECREF(testMethod);
                }
                Py_DECREF(fooInstance);
            }
            Py_DECREF(fooCls);
        }
        Py_DECREF(myModule);
    }

    // 关闭Python解释器,回收资源
    Py_Finalize();
    return 0;
}
注意事项
  • 不要尝试通过hack手段跳过模块顶层代码执行,否则会导致模块内的类、函数无法正常注册,后续调用必然失败。
  • 所有通过Python C API获取到的PyObject*对象,在不再使用时都需要调用Py_DECREF减少引用计数,嵌入式场景长期运行如果漏写会出现严重的内存泄漏问题。
  • 调用Python对象前最好通过PyCallable_Check校验对象是否可调用,避免空指针或类型错误导致程序崩溃。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 09:36:16