在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


欢迎大家一起交流讨论!

相关推荐
荒古前5 分钟前
龟兔赛跑 PTA
c语言·算法
Algorithm15769 分钟前
云原生相关的 Go 语言工程师技术路线(含博客网址导航)
开发语言·云原生·golang
岑梓铭9 分钟前
(CentOs系统虚拟机)Standalone模式下安装部署“基于Python编写”的Spark框架
linux·python·spark·centos
努力学习的小廉9 分钟前
深入了解Linux —— make和makefile自动化构建工具
linux·服务器·自动化
MZWeiei13 分钟前
Zookeeper基本命令解析
大数据·linux·运维·服务器·zookeeper
shinelord明18 分钟前
【再谈设计模式】享元模式~对象共享的优化妙手
开发语言·数据结构·算法·设计模式·软件工程
游客52023 分钟前
opencv中的各种滤波器简介
图像处理·人工智能·python·opencv·计算机视觉
Monly2124 分钟前
Java(若依):修改Tomcat的版本
java·开发语言·tomcat
boligongzhu25 分钟前
DALSA工业相机SDK二次开发(图像采集及保存)C#版
开发语言·c#·dalsa
Eric.Lee202125 分钟前
moviepy将图片序列制作成视频并加载字幕 - python 实现
开发语言·python·音视频·moviepy·字幕视频合成·图像制作为视频