【ARM-Linux篇】C语言调用Python

一、搭建编译环境

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

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

dpkg -l | grep libpython3

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

 pg@pg-Default-string:~$ dpkg -l | grep libpython
ii 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 (standard
library, version 3.10)

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

sudo apt install libpython3.10-dev 

二、直接调用python语句

先看这么一个简单的例子:

#include "Python.h"

int main()
{
    Py_Initialize(); // 初始化
    PyRun_SimpleString("print ('funny')");
    Py_Finalize(); //释放资源
}

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

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

输出:

funny 

代码解释:
• 首先包含Python.h头文件,这是Python API的头文件,用于访问Python对象和函数
• 其次在程序开始时使用Py_Initialize()函数初始化Python解释器。这样可以在C程序中执行Python代码
• 然后使用PyRun_SimpleString()函数执行一段简单的Python代码,例如打印"funny"。需要传递一个字符串作为参数,表示要执行的Python代码,如print ('funny')这么一个Python代码字符串。 

• 最后在程序结束时使用Py_Finalize()函数关闭Python解释器,并释放资源。

三、调用无参python函数

把如下语句放到nopara.py的文件的函数里:

#nopara.py文件
def say_funny():
    print('funny')

接下来用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();

    PyObject *sys = PyImport_ImportModule("sys");
    PyObject *path = PyObject_GetAttrString(sys,"path");
    PyList_Append(path,PyUnicode_FromString("."));//PyUnicode_FromString:将C字符串转化为Python字符串

    PyObject *pModule = PyImport_ImportModule("nopara");
    if(!pModule){
        PyErr_Print();
        printf("Error:failed to load nopara.py\n");
    }

    PyObject *pFunc = PyObject_GetAttrString(pModule,"say_funny");
    if(!pFunc){
        PyErr_Print();
        printf("Error:failed to load say_funny\n");
    }

    PyObject *pValue = PyObject_CallObject(pFunc,NULL);
    if(!pValue){
        PyErr_Print();
        printf("Error:function call failed\n");
    }

    Py_DECREF(pValue);
    Py_DECREF(pFunc);
    Py_DECREF(pModule);

    Py_Finalize();

    return 0;
}

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

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

 输出:

funny

四、调用有参python函数

把如下语句放到para.py的文件的函数里:

#para.py文件
def say_funny(category):
    print(category)
    return category

接下来用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>

int main()
{
    Py_Initialize();

    PyObject *sys = PyImport_ImportModule("sys");
    PyObject *path = PyObject_GetAttrString(sys,"path");
    PyList_Append(path,PyUnicode_FromString("."));

    PyObject *pModule = PyImport_ImportModule("para");
    if(!pModule){
        PyErr_Print();
        printf("Error:failed to load para.py\n");
    }

    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);

    PyObject *pValue = PyObject_CallObject(pFunc,pArgs);
    if(!pValue){
        PyErr_Print();
        printf("Error:function call failed\n");
    }
    //调用有参新内容
    char *result = NULL;

    if(!PyArg_Parse(pValue,"s",&result)){
        PyErr_Print();
        printf("Error:parse failed");
    }
    printf("result=%s\n",result);

    Py_DECREF(pValue);
    Py_DECREF(pFunc);
    Py_DECREF(pModule);

    Py_Finalize();

    return 0;
}

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

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

输出:

comedy

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序猿gao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值