在Linux环境底下 用C语言执行Python程序

在Linux环境底下 用C语言执行Python程序

文章目录

  • [在Linux环境底下 用C语言执行Python程序](#在Linux环境底下 用C语言执行Python程序)

1、环境安装&检测

  • 通过C语言调用Python代码,需要先安装libpython3的 dev依赖库(不同的ubuntu版本下,python版本 可能会有差异, 比如ubuntu 22.04里是libpython3.10-dev)。

  • 首先可以通过以下命令验证是否是否已经存在python3的dev包

  • dpkg -l | grep libpython3

    -->正常会有类似如下的输出,出现"libpython3"和 "dev",如libpython3.10-dev即可:

    c 复制代码
    pg@pg-Default-string:~$ dpkg -l | grep libpythonii libpython3-dev:amd64 3.10.6-1~22.04
    amd64 header files and a static library for Python (default)
    ii libpython3-stdlib:amd64 3.10.6-1~22.04 amd64 interactive high-level object-oriented language (default python3 version)
    ii libpython3.10:amd64 3.10.12-1~22.04.2 amd64 Shared Python runtime library (version 3.10)
    ii libpython3.10-dev:amd64 3.10.12-1~22.04.2 amd64 Header files and a static library for Python (v3.10)
    ii libpython3.10-minimal:amd64 3.10.12-1~22.04.2 amd64 Minimal subset of the Python language (version 3.10)
    ii libpython3.10-stdlib:amd64 3.10.12-1~22.04.2 amd64 Interactive high-level object-oriented language (standardlibrary, version 3.10)

    --> 如果没有, 可以通过apt命令安装相关的dev包:

    c 复制代码
    sudo apt install libpython3.10-dev
    Orangepi Zero2 //全志H616开发学习文档 

2、C语言调用Python语句

2.1 直接调用python语句

  • 我们先来一个简单的例子
c 复制代码
// simpledemo.c
#include "Python.h"
int main()
{
	Py_Initialize(); // 初始化
	//int PyRun_SimpleString(const char *command)
    PyRun_SimpleString("print ('funny')");
    Py_Finalize(); //释放资源; 最后在程序结束时使用Py_Finalize()函数关闭Python解释器,并释放资源
}

然要编译和运行这个程序,可以使用以下命令(假设使用的是gcc编译器和Python 3.10版本):

gcc simpledemo.c -o simpledemo -I /usr/include/python3.10 -l python3.10 ./simpledemo

-->正常输出

c 复制代码
funny

2.2 调用无参python函数

  • 上文调用了print ('funny')这条语句,现在把这条语句放到 nopara.py的文件的函数里, 如下
c 复制代码
#nopara.py文件
def say_funny():
	print('funny')

接下来用C语言进行调用,注意文件后缀。

c 复制代码
//nopara.c
#if 0
1、包含Python.h头文件,以便使用Python API。
2、使用void Py_Initialize()初始化Python解释器,
3、使用PyObject *PyImport_ImportModule(const char *name)和PyObject
*PyObject_GetAttrString(PyObject *o, const char *attr_name)获取sys.path对象,并利用
int PyList_Append(PyObject *list, PyObject *item)将当前路径.添加到sys.path中,以便加载
当前的Python模块(Python文件即python模块)。
4、使用PyObject *PyImport_ImportModule(const char *name)函数导入Python模块,并检查是否
有错误。
5、使用PyObject *PyObject_GetAttrString(PyObject *o, const char *attr_name)函数获取
Python函数对象,并检查是否可调用。
6、使用PyObject *PyObject_CallObject(PyObject *callable, PyObject *args)函数调用
Python函数,并获取返回值。
7、使用void Py_DECREF(PyObject *o)函数释放所有引用的Python对象。
8、结束时调用void Py_Finalize()函数关闭Python解释器。
相关的函数参数说明参考网站(网站左上角输入函数名即可开始搜索):
https://docs.python.org/zh-cn/3/c-api/import.html
#endif

#include <Python.h>
int main()
{
    Py_Initialize();//创建新的python环境,加载所有内置模块和扩展模块,-->c中执行py
    // 将当前路径添加到sys.path中
    PyObject *sys = PyImport_ImportModule("sys");
    PyObject *path = PyObject_GetAttrString(sys, "path");//获取引用
    PyList_Append(path, PyUnicode_FromString("."));
    //将当前路径.添加到sys.path中,以便加载当前的Python模块(Python文件即python模块)。

    // 导入nopara模块
    PyObject *pModule = PyImport_ImportModule("nopara");
    if (!pModule)
    {
        PyErr_Print();
        printf("ERROR: failed to load nopara.py\n");
        return 1;
    }
    // 获取say_funny函数对象
    PyObject *pFunc = PyObject_GetAttrString(pModule, "say_funny");
    if (!pFunc || !PyCallable_Check(pFunc))
    {
        PyErr_Print();
        printf("ERROR: function say_funny not found or not callable\n");
        return 1;
    }
    // 调用say_funny函数并获取返回值
    PyObject *pValue = PyObject_CallObject(pFunc, NULL);
    if (!pValue)
    {
        PyErr_Print();
        printf("ERROR: function call failed\n");
        return 1;
    }
    // 释放所有引用的Python对象
    Py_DECREF(pValue);
    Py_DECREF(pFunc);
    Py_DECREF(pModule);
    // 关闭Python解释器
    Py_Finalize();
    return 0;
}

要编译和运行这个程序,可以使用以下命令(假设使用的是gcc编译器和Python 3.10版本)

gcc -o nopara nopara.c -I /usr/include/python3.10/ -l python3.10 ./nopara

-->正常输出

c 复制代码
funny

2.3 调用有参python函数

  • C语言调用python有参函数,首先定义一个带参数和返回值的函数
c 复制代码
#nopara.py文件
import sys

def say_funny(s):
    print('funny')
    return s
# print(sys.path)

接下来用C语言进行调用,调用的流程无参函数的调用方式几乎是一样的是的:

c 复制代码
//nopara.c
#if 0
1、包含Python.h头文件,以便使用Python API。
2、使用void Py_Initialize()初始化Python解释器,
3、使用PyObject *PyImport_ImportModule(const char *name)和PyObject
*PyObject_GetAttrString(PyObject *o, const char *attr_name)获取sys.path对象,并利用
int PyList_Append(PyObject *list, PyObject *item)将当前路径.添加到sys.path中,以便加载
当前的Python模块(Python文件即python模块)。
4、使用PyObject *PyImport_ImportModule(const char *name)函数导入Python模块,并检查是否
有错误。
5、使用PyObject *PyObject_GetAttrString(PyObject *o, const char *attr_name)函数获取
Python函数对象,并检查是否可调用。
+6、使用PyObject *Py_BuildValue(const char *format, ...)函数将C类型的数据结构转换成
Python对象,作为Python函数的参数,没有参数不需要调用
7、使用PyObject *PyObject_CallObject(PyObject *callable, PyObject *args)函数调用
Python函数,并获取返回值。
+8、使用int PyArg_Parse(PyObject *args, const char *format, ...)函数将返回值转换为C类
型,并检查是否有错误,没有返回值时不需要调用。
9、使用void Py_DECREF(PyObject *o)函数释放所有引用的Python对象。
10、结束时调用void Py_Finalize()函数关闭Python解释器。
相关的函数参数说明参考网站(网站左上角输入函数名即可开始搜索):
https://docs.python.org/zh-cn/3/c-api/import.html
#endif

#include <Python.h>//包含Python.h头文件,以便使用Python API。
int main()
{
    Py_Initialize();//使用void Py_Initialize()初始化Python解释器,
    // 将当前路径添加到sys.path中
    PyObject *sys = PyImport_ImportModule("sys");//初始化python解释器
    PyObject *path = PyObject_GetAttrString(sys, "path");
    PyList_Append(path, PyUnicode_FromString("."));
    // 导入para模块
    PyObject *pModule = PyImport_ImportModule("para");
    if (!pModule)
    {
        PyErr_Print();
        printf("Error: failed to load nopara.py\n");
    }
    //获取say_funny函数对象
    PyObject *pFunc = PyObject_GetAttrString(pModule, "say_funny");
    if (!pFunc)
    {
        PyErr_Print();
        printf("Error: failed to load say_funny\n");
    }
    //创建一个字符串作为参数
    char *category = "comedy";
    PyObject *pArgs = Py_BuildValue("(s)", category);
    //调用say_funny函数并获取返回值
    PyObject *pValue = PyObject_CallObject(pFunc, pArgs);
    if (!pValue)
    {
        PyErr_Print();
        printf("Error: function call failed\n");
    } 
    //将返回值转换为C类型
    char *result = NULL;
    
    if (!PyArg_Parse(pValue, "s", &result))
    {
        PyErr_Print();
        printf("Error: parse failed\n");
    }
    //打印返回值
    printf("pValue=%s\n", result);
    //释放所有引用的Python对象
    Py_DECREF(pValue);
    Py_DECREF(pFunc);
    Py_DECREF(pModule);
    //释放所有引用的Python对象
    Py_Finalize();
    return 0;
}

这里要注意的是,Py_BuildValue的第一个参数是类型转换:C对应的Python的数据类型转换对应的格式 如下:

C 对应 Python 数据类型格式
  • 然要编译和运行这个程序,可以使用以下命令(假设使用的是gcc编译器和Python 3.10版本)

gcc para.c -o para -I /usr/include/python3.10 -l python3.10 ./para

-->正常输出

c 复制代码
funny
pValue=comedy


欢迎大家一起交流讨论!

相关推荐
宅小海16 分钟前
scala String
大数据·开发语言·scala
朝九晚五ฺ17 分钟前
【Linux探索学习】第十四弹——进程优先级:深入理解操作系统中的进程优先级
linux·运维·学习
小喵要摸鱼18 分钟前
Python 神经网络项目常用语法
python
qq_3273427318 分钟前
Java实现离线身份证号码OCR识别
java·开发语言
锅包肉的九珍19 分钟前
Scala的Array数组
开发语言·后端·scala
自由的dream20 分钟前
Linux的桌面
linux
心仪悦悦23 分钟前
Scala的Array(2)
开发语言·后端·scala
yqcoder1 小时前
reactflow 中 useNodesState 模块作用
开发语言·前端·javascript
xiaozhiwise1 小时前
Makefile 之 自动化变量
linux
baivfhpwxf20231 小时前
C# 5000 转16进制 字节(激光器串口通讯生成指定格式命令)
开发语言·c#