C语言调用Python脚本

C语言调用Python脚本,第1张

目录

一、头文件

二、使用步骤

1.初始化python模块

2.设置python的搜索路径

3.导入python脚本

 4.导入调用的方法

5.构建参数

6.调用方法 

7.解析返回值 

8.释放资源

三、程序示例

四、编译


一、头文件
#include 

或者使用其他版本的python也可以。

如若头文件不存在,请执行如下命令安装

apt-get install python3-dev
二、使用步骤 1.初始化python模块
void Py_Initialize();

初始化完成后,可以调用函数Py_IsInitialized()来判断初始化是否成功。

/*
 Return true (nonzero) when the Python interpreter has been initialized,
 false (zero) if not. 
*/
int Py_IsInitialized();

成功返回 true(非0值),失败返回 false(0)

使用完毕后需要使用对应的函数Py_Finalize()来释放python资源,一般来说Py_Initialize和Py_Finalize应该是成对出现的。

void Py_Finalize();
/*
This is a backwards-compatible version of Py_FinalizeEx() that disregards the return value.
*/


int Py_FinalizeEx();
/*Part of the Stable ABI since version 3.6.
Undo all initializations made by Py_Initialize() and subsequent use of Python/C API 
functions, and destroy all sub-interpreters (see Py_NewInterpreter() below) that were 
created and not yet destroyed since the last call to Py_Initialize(). Ideally, this frees  
 all memory allocated by the Python interpreter. This is a no-op when called for a second
 time (without calling Py_Initialize() again first). Normally the return value is 0. If 
there were errors during finalization (flushing buffered data), -1 is returned.

This function is provided for a number of reasons. An embedding application might want to 
restart Python without having to restart the application itself. An application that has 
loaded the Python interpreter from a dynamically loadable library (or DLL) might want to 
free all memory allocated by Python before unloading the DLL. During a hunt for memory 
leaks in an application a developer might want to free all memory allocated by Python 
before exiting from the application.

Bugs and caveats: The destruction of modules and objects in modules is done in random 
order; this may cause destructors (__del__() methods) to fail when they depend on other 
objects (even functions) or modules. Dynamically loaded extension modules loaded by 
Python are not unloaded. Small amounts of memory allocated by the Python interpreter may 
not be freed (if you find a leak, please report it). Memory tied up in circular 
references between objects is not freed. Some memory allocated by extension modules may
 not be freed. Some extensions may not work properly if their initialization routine is 
called more than once; this can happen if an application calls Py_Initialize() and 
Py_FinalizeEx() more than once.

Raises an auditing event cpython._PySys_ClearAuditHooks with no arguments.*/

对于Py_Finalize(),是Py_FinalizeEx()的向后兼容版本,它会忽略返回值。

Py_FinalizeEx()如上所示为官方文档解释的原话,主要作用就是释放资源。

2.设置python的搜索路径
//相当于在python中的import sys语句。

这个函数相当于直接运行python语句 PyRun_SimpleString("import sys"); //是将搜索路径设置为当前目录。

PyRun_SimpleString("sys.path.append('./')");

PyRun_SimpleString()这个函数相当于直接运行python语句,将搜索路径设置为你所调用的python脚本所在的路径,其目的是为了找到导入的python脚本,为下一步做准备。

3.导入python脚本
/*
参数:
    name - 需要调用python脚本的名称(不包括.py)
返回值:
    成功返回PyObject指针,失败返回NULL
*/
PyObject *PyImport_ImportModule(const char *name);
 4.导入调用的方法
/*
参数:
    pmodule - PyImport_ImportModule的返回值
    name - 函数名
返回值:
    成功返回PyObject指针,失败返回NULL
*/
PyObject *PyObject_GetAttrString(PyObject *pmodule, const char *name);
5.构建参数

如果需要想python脚本传递参数的话需要构建参数,参数类型不定,可以是整型、浮点型、字符串,包括元组类型等都可以传入。

一般会用到PyTuple_New,Py_BuildValue,PyTuple_SetItem等几个函数。

/*
构建python参数
*/
PyObject *Py_BuildValue(const char *format, ...);

对于Py_BuildValue函数中format格式的说明如下:

在下面的描述中,圆括号 () 内的是格式单元将要返回的 Python 对象类型;方括号 [] 内的是传递的 C 变量(变量集)的类型。

字符例如空格,制表符,冒号和逗号在格式化字符串中会被忽略(但是不包括格式单元,如 s#)。

这可以使很长的格式化字符串具有更好的可读性。


s (str 或 None) [const char *]

使用 'utf-8' 编码将空终止的 C 字符串转换为 Python str 对象。

如果 C 字符串指针为 NULL,则使用 None

s# (str 或 None) [const char *, Py_ssize_t]

使用 'utf-8' 编码将 C 字符串及其长度转换为 Python str 对象。

如果 C 字符串指针为 NULL,则长度将被忽略,并返回 None

y (bytes) [const char *]

这将 C 字符串转换为 Python bytes 对象。

如果 C 字符串指针为 NULL,则返回 None

y# (bytes) [const char *, Py_ssize_t]

这会将 C 字符串及其长度转换为一个 Python 对象。

如果该 C 字符串指针为 NULL,则返回 None

z (str or None) [const char *]

和 s 一样。

z# (str 或 None) [const char *, Py_ssize_t]

和 s# 一样。

u (str) [const wchar_t *]

将空终止的 wchar_t 的 Unicode (UTF-16 或 UCS-4) 数据缓冲区转换为 Python Unicode 对象。

如果 Unicode 缓冲区指针为 NULL,则返回 None

u# (str) [const wchar_t *, Py_ssize_t]

将 Unicode (UTF-16 或 UCS-4) 数据缓冲区及其长度转换为 Python Unicode 对象。

如果 Unicode 缓冲区指针为 NULL,则长度将被忽略,并返回 None

U (str 或 None) [const char *]

和 s 一样。

U# (str 或 None) [const char *, Py_ssize_t]

和 s# 一样。

i (int) [int]

将一个 C int 整型转化成 Python 整型对象。

b (int) [char]

将一个 C char 字符型转化成 Python 整型对象。

h (int) [short int]

将一个 C short int 短整型转化成 Python 整型对象。

l (int) [long int]

将一个 C long int 长整型转化成 Python 整型对象。

B (int) [unsigned char]

将一个 C unsigned char 无符号字符型转化成 Python 整型对象。

H (int) [unsigned short int]

将一个 C unsigned long 无符号短整型转化成 Python 整型对象。

I (int) [unsigned int]

将一个 C unsigned long 无符号整型转化成 Python 整型对象。

k (int) [unsigned long]

将一个 C unsigned long 无符号长整型转化成 Python 整型对象。

L (int) [long long]

将一个 C long long 长长整形转化成 Python 整形对象。

K (int) [unsigned long long]

将一个 C unsigned long long 无符号长长整型转化成 Python 整型对象。

n (int) [Py_ssize_t]

将一个 C Py_ssize_t 类型转化为 Python 整型。

c (bytes 长度为1 ) [char]

将一个 C int 整型代表的字符转化为 Python bytes 长度为 1 的字节对象。

C (str 长度为 1) [int]

将一个 C int 整型代表的字符转化为 Python str 长度为 1 的字符串对象。

d (float) [double]

将一个 C double 双精度浮点数转化为 Python 浮点数类型数字。

f (float) [float]

将一个 C float 单精度浮点数转化为 Python 浮点数类型数字。

D (complex) [Py_complex *]

将一个 C Py_complex 类型的结构转化为 Python 复数类型。

O (object) [PyObject *]

将 Python 对象传递不变(其引用计数除外,该计数由 1 递增)。

如果传入的对象是 NULL 指针,则假定这是由于生成参数的调用发现错误并设置异常而引起的。

因此,Py_BuildValue() 将返回 NULL,但不会引发异常。

如果尚未引发异常,则设置 SystemError

S (object) [PyObject *]

和 O 相同。

N (object) [PyObject *]

和 O 相同,然而它并不增加对象的引用计数。

当通过调用参数列表中的对象构造器创建对象时很实用。

O& (object) [converter, anything]

通过 converter 函数将 anything 转换为 Python 对象。

该函数调用时会传入 anything (应与 void* 兼容) 作为参数并且应当返回一个“新的”Python 对象,或者当发生错误时返回 NULL

(items) (tuple) [matching-items]

将一个 C 变量序列转换成 Python 元组并保持相同的元素数量。

[items] (list) [相关的元素]

将一个 C 变量序列转换成 Python 列表并保持相同的元素数量。

{items} (dict) [相关的元素]

将一个C变量序列转换成 Python 字典。

每一对连续的 C 变量对作为一个元素插入字典中,分别作为关键字和值。

 构建示例:

//构建一个整型参数
PyObject *pArg = Py_BuildValue("i", 5);
//构建两个参数一个整型,一个浮点型
PyObject *pArg = Py_BuildValue("(i, f)", 5, 2.4);
/*
构建元组
参数:
    size - 元组的大小
*/
PyObject *PyTuple_New(Py_ssize_t size);

 构建元组的函数很简单,参数为构建的元组的大小。

但是构建完元组之后还需要构建元组中的每一位元素,构建完之后就需要用到如下函数。

/*
说明:
    在 p 指向的元组的 pos 位置插入对对象 o 的引用
参数:
    p - 这应该是一个元组
    pos - 元组中的位置0-n
    o - 要插入元组p的对象
返回值:
    成功时返回 0; 如果 pos 越界,则返回 -1,并抛出一个 IndexError 异常。

*/ int PyTuple_SetItem(PyObject *p, Py_ssize_t pos, PyObject *o); 

构建示例:

PyObject *pInt = Py_BuildValue("i", 3);        //构建整型

PyObject *pFloat = Py_BuildValue("f", 2.1);    //构建浮点型

PyObject *pyTupleList = PyTuple_New(2);        //创建大小为2的元组

PyTuple_SetItem(pyTupleList, 0, pInt);         //在第1个位置插入pInt

PyTuple_SetItem(pyTupleList, 1, pFloat);       //在第2个位置插入pFloat
6.调用方法 
/*
说明:
    调用方法,返回结果
参数:
    callable_object - 方法,PyObject_GetAttrString返回的对象
    args - 传入的参数,可以为NULL
返回值:
    成功时返回结果,在失败时抛出一个异常并返回 NULL
*/
PyObject *PyObject_CallObject(PyObject *callable_object, PyObject *args);
//PyEval_CallObject在新版本中已被弃用

可以看到,这里的参数args只有一个,所以在传入多个参数时,可以构建元组传入。

7.解析返回值 
/*
说明:
    解析函数调用的返回值,并保存
参数:
    args - PyObject_CallObject的返回
返回值:
    成功返回true,失败返回false
*/
int PyArg_Parse(PyObject *args, const char *format, ...);

/*
说明:
    解析函数调用的返回值,并保存(可解析元组,多个参数)
参数:
    args - PyObject_CallObject的返回
返回值:
    成功返回true,失败返回false
*/
int PyArg_ParseTuple(PyObject *args, const char *format, ...);

 PyArg_Parse()和PyArg_ParseTuple()的format与Py_BuildValue部分类似,说明如下:

字符串和缓存区

这些格式允许将对象按照连续的内存块形式进行访问。

你没必要提供返回的 unicode 字符或者字节区的原始数据存储。

s (str) [const char *]

将一个 Unicode 对象转换成一个指向字符串的 C 指针。

一个指针指向一个已经存在的字符串,这个字符串存储的是传如的字符指针变量。

C 字符串是已空结束的。

Python 字符串不能包含嵌入的无效的代码点;如果由,一个 ValueError 异常会被引发。

Unicode 对象被转化成 'utf-8' 编码的 C 字符串。

如果转换失败,一个 UnicodeError 异常被引发。

s* (str or bytes-like object) [Py_buffer]

这个表达式既接受 Unicode 对象也接受类字节类型对象。

它为由调用者提供的 Py_buffer 结构赋值。

这里结果的 C 字符串可能包含嵌入的 NUL 字节。

Unicode 对象通过 'utf-8' 编码转化成 C 字符串。

s# (str, read-only bytes-like object) [const char *, Py_ssize_t]

像 s*,除了它不接受易变的对象。

结果存储在两个 C 变量中,第一个是指向 C 字符串的指针,第二个是它的长度。

字符串可能包含嵌入的 null 字节。

Unicode 对象都被通过 'utf-8' 编码转化成 C 字符串。

z (str or None) [const char *]

与 s 类似,但 Python 对象也可能为 None,在这种情况下,C 指针设置为 NULL

z* (str, bytes-like object or None) [Py_buffer]

与 s* 类似,但 Python 对象也可能为 None,在这种情况下,Py_buffer 结构的 buf 成员设置为 NULL

z# (str, read-only bytes-like object 或者 None) [const char *, Py_ssize_t]

与 s# 类似,但 Python 对象也可能为 None,在这种情况下,C 指针设置为 NULL

y (read-only bytes-like object) [const char *]

这个表达式将一个类字节类型对象转化成一个指向字符串的 C 指针;它不接受 Unicode 对象。

字节缓存区必须不包含嵌入的 null 字节;如果包含了 null 字节,会引发一个 ValueError 异常。

在 3.5 版更改: 以前,当字节缓冲区中遇到了嵌入的 null 字节会引发 TypeError 。

y* (bytes-like object) [Py_buffer]

s* 的变式,不接受 Unicode 对象,只接受类字节类型变量。

这是接受二进制数据的推荐方法。

y# (read-only bytes-like object) [const char *, Py_ssize_t]

s# 的变式,不接受 Unicode 对象,只接受类字节类型变量。

S (bytes) [PyBytesObject *]

要求 Python 对象为 bytes 对象,不尝试进行任何转换。

如果该对象不为 bytes 对象则会引发 TypeError

C 变量也可被声明为 PyObject* 类型。

Y (bytearray) [PyByteArrayObject *]

要求 Python 对象为 bytearray 对象,不尝试进行任何转换。

如果该对象不为 bytearray 对象则会引发 TypeError

C 变量也可被声明为 PyObject* 类型。

u (str) [const Py_UNICODE *]

将一个 Python Unicode 对象转化成指向一个以空终止的 Unicode 字符缓冲区的指针。

你必须传入一个 Py_UNICODE 指针变量的地址,存储了一个指向已经存在的 Unicode 缓冲区的指针。

请注意一个 Py_UNICODE 类型的字符宽度取决于编译选项(16 位或者 32 位)。

Python 字符串必须不能包含嵌入的 null 代码点;如果有,引发一个 ValueError 异常。

在 3.5 版更改: 以前,当 Python 字符串中遇到了嵌入的 null 代码点会引发 TypeError 。

Deprecated since version 3.3, will be removed in version 3.12: 这是旧版样式 Py_UNICODE API; 请迁移至 PyUnicode_AsWideCharString().

u# (str) [const Py_UNICODE *, Py_ssize_t]

u 的变式,存储两个 C 变量,第一个指针指向一个 Unicode 数据缓存区,第二个是它的长度。

它允许 null 代码点。

Deprecated since version 3.3, will be removed in version 3.12: 这是旧版样式 Py_UNICODE API; 请迁移至 PyUnicode_AsWideCharString().

Z (str 或 None) [const Py_UNICODE *]

与 u 类似,但 Python 对象也可能为 None,在这种情况下 Py_UNICODE 指针设置为 NULL

Deprecated since version 3.3, will be removed in version 3.12: 这是旧版样式 Py_UNICODE API; 请迁移至 PyUnicode_AsWideCharString().

Z# (str 或 None) [const Py_UNICODE *, Py_ssize_t]

与 u# 类似,但 Python 对象也可能为 None,在这种情况下 Py_UNICODE 指针设置为 NULL

Deprecated since version 3.3, will be removed in version 3.12: 这是旧版样式 Py_UNICODE API; 请迁移至 PyUnicode_AsWideCharString().

U (str) [PyObject *]

要求 Python 对象为 Unicode 对象,不尝试进行任何转换。

如果该对象不为 Unicode 对象则会引发 TypeError

C 变量也可被声明为 PyObject*。

w* (可读写 bytes-like object) [Py_buffer]

这个表达式接受任何实现可读写缓存区接口的对象。

它为调用者提供的 Py_buffer 结构赋值。

缓冲区可能存在嵌入的 null 字节。

当缓冲区使用完后调用者需要调用 PyBuffer_Release()

es (str) [const char *encoding, char **buffer]

s 的变式,它将编码后的 Unicode 字符存入字符缓冲区。

它只处理没有嵌 NUL 字节的已编码数据。

此格式需要两个参数。

第一个仅用作输入,并且必须为 const char*,它指向一个以 NUL 结束的字符串表示的编码格式名称,或者为 NULL,这表示使用 'utf-8' 编码格式。

如果为 Python 无法识别的编码格式名称则会引发异常。

第二个参数必须为 char**;它所引用的指针值将被设为带有参数文本内容的缓冲区。

文本将以第一个参数所指定的编码格式进行编码。

PyArg_ParseTuple() 会分配一个足够大小的缓冲区,将编码后的数据拷贝进这个缓冲区并且设置 *buffer 引用这个新分配的内存空间。

调用者有责任在使用后调用 PyMem_Free() 去释放已经分配的缓冲区。

et (strbytes or bytearray) [const char *encoding, char **buffer]

和 es 相同,除了不用重编码传入的字符串对象。

相反,它假设传入的参数是编码后的字符串类型。

es# (str) [const char *encoding, char **buffer, Py_ssize_t *buffer_length]

s# 的变式,它将已编码的 Unicode 字符存入字符缓冲区。

不像 es 表达式,它允许传入的数据包含 NUL 字符。

它需要三个参数。

第一个仅用作输入,并且必须为 const char*,它指向一个编码格式名称,形式为以 NUL 结束的字符串或 NULL,在后一种情况下将使用 'utf-8' 编码格式。

如果编码格式名称无法被 Python 识别则会引发异常。

第二个参数必须为 char**;它所引用的指针值将被设为带有参数文本内容的缓冲区。

文本将以第一个参数所指定的编码格式进行编码。

第三个参数必须为指向一个整数的指针;被引用的整数将被设为输出缓冲区中的字节数。

有两种 *** 作方式:

如果 *buffer 指向 NULL 指针,则函数将分配所需大小的缓冲区,将编码的数据复制到此缓冲区,并设置 *buffer 以引用新分配的存储。

呼叫者负责调用 PyMem_Free() 以在使用后释放分配的缓冲区。

如果 *buffer 指向非 NULL 指针(已分配的缓冲区),则 PyArg_ParseTuple() 将使用此位置作为缓冲区,并将 *buffer_length 的初始值解释为缓冲区大小。

然后,它将将编码的数据复制到缓冲区,并终止它。

如果缓冲区不够大,将设置一个 ValueError

在这两个例子中,*buffer_length 被设置为编码后结尾不为 NUL 的数据的长度。

et# (strbytes 或 bytearray) [const char *encoding, char **buffer, Py_ssize_t *buffer_length]

和 es# 相同,除了不用重编码传入的字符串对象。

相反,它假设传入的参数是编码后的字符串类型。

数字

b (int) [unsigned char]

将一个非负的 Python 整型转化成一个无符号的微整型,存储在一个 C unsigned char 类型中。

B (int) [unsigned char]

将一个 Python 整型转化成一个微整型并不检查溢出问题,存储在一个 C unsigned char 类型中。

h (int) [short int]

将一个 Python 整型转化成一个 C short int 短整型。

H (int) [unsigned short int]

将一个 Python 整型转化成一个 C unsigned short int 无符号短整型,并不检查溢出问题。

i (int) [int]

将一个 Python 整型转化成一个 C int 整型。

I (int) [unsigned int]

将一个 Python 整型转化成一个 C unsigned int 无符号整型,并不检查溢出问题。

l (int) [long int]

将一个 Python 整型转化成一个 C long int 长整型。

k (int) [unsigned long]

将一个Python整型转化成一个C unsigned long int 无符号长整型,并不检查溢出问题。

L (int) [long long]

将一个 Python 整型转化成一个 C long long 长长整型。

K (int) [unsigned long long]

将一个 Python 整型转化成一个 C unsigned long long 无符号长长整型,并不检查溢出问题。

n (int) [Py_ssize_t]

将一个 Python 整型转化成一个 C Py_ssize_t Python 元大小类型。

c (bytes 或者 bytearray 长度为 1) [char]

将一个 Python 字节类型,如一个长度为 1 的 bytes 或者 bytearray 对象,转化成一个 C char 字符类型。

在 3.3 版更改: 允许 bytearray 类型的对象。

C (str 长度为 1) [int]

将一个 Python 字符,如一个长度为 1 的 str 字符串对象,转化成一个 C int 整型类型。

f (float) [float]

将一个 Python 浮点数转化成一个 C float 浮点数。

d (float) [double]

将一个Python浮点数转化成一个C double 双精度浮点数。

D (complex) [Py_complex]

将一个 Python 复数类型转化成一个 C Py_complex Python 复数类型。

其他对象

O (object) [PyObject *]

将 Python 对象(不进行任何转换)存储在 C 对象指针中。

因此,C 程序接收已传递的实际对象。

对象的引用计数不会增加。

存储的指针不是 NULL

O! (object) [typeobject, PyObject *]

将一个 Python 对象存入一个 C 对象指针。

这类似于 O,但是接受两个 C 参数:第一个是 Python 类型对象的地址,第二个是存储对象指针的 C 变量 (类型为 PyObject*) 的地址。

如果 Python 对象不具有所要求的类型,则会引发 TypeError

O& (object) [converter, anything]

通过一个 converter 函数将一个 Python 对象转换为一个 C 变量。

此函数接受两个参数:第一个是函数,第二个是 C 变量 (类型任意) 的地址,转换为 void* 类型。

 converter 函数将以如下方式被调用:

status = converter(object, address);

其中 object 是待转换的 Python 对象而 address 为传给 PyArg_Parse* 函数的 void* 参数。

返回的 status 应当以 1 代表转换成功而以 0 代表转换失败。

当转换失败时,converter 函数应当引发异常并且会让 address 的内容保持未修改状态。

如果 converter 返回 Py_CLEANUP_SUPPORTED,则如果参数解析最终失败,它可能会再次调用该函数,从而使转换器有机会释放已分配的任何内存。

在第二个调用中,object 参数将为 NULL;因此,该参数将为 NULL;因此,该参数将为 NULL,因此,该参数将为 NULL``(如果值)为 ``NULL address 的值与原始呼叫中的值相同。

在 3.1 版更改: Py_CLEANUP_SUPPORTED 被添加。

p (bool) [int]

测试传入的值是否为真(一个布尔判断)并且将结果转化为相对应的 C true/false 整型值。

如果表达式为真置 1,假则置 0

它接受任何合法的 Python 值。

参见 逻辑值检测 获取更多关于 Python 如何测试值为真的信息。

3.3 新版功能.

(items) (tuple) [matching-items]

对象必须是 Python 序列,它的长度是 items 中格式单元的数量。

C 参数必须对应 items 中每一个独立的格式单元。

序列中的格式单元可能有嵌套。

传递 "long" 整型(整型的值超过了平台的 LONG_MAX 限制)是可能的,然而没有进行适当的范围检测——当接收字段太小而接收不到值时,最重要的位被静默地截断(实际上,C 语言会在语义继承的基础上强制类型转换——期望的值可能会发生变化)。

格式化字符串中还有一些其他的字符具有特殊的涵义。

这些可能并不嵌套在圆括号中。

它们是:

|

表明在 Python 参数列表中剩下的参数都是可选的。

C 变量对应的可选参数需要初始化为默认值——当一个可选参数没有指定时, PyArg_ParseTuple() 不能访问相应的 C 变量(变量集)的内容。

$

PyArg_ParseTupleAndKeywords() only:表明在 Python 参数列表中剩下的参数都是强制关键字参数。

当前,所有强制关键字参数都必须也是可选参数,所以格式化字符串中 | 必须一直在 $ 前面。

3.3 新版功能.

:

格式单元的列表结束标志;冒号后的字符串被用来作为错误消息中的函数名(PyArg_ParseTuple() 函数引发的“关联值”异常)。

;

格式单元的列表结束标志;分号后的字符串被用来作为错误消息取代默认的错误消息。

 : 和 ; 相互排斥。

 解析示例:

//单个参数解析 a = 1
PyArg_Parse(result, "i", &a);

//单个参数解析 f('strings')
PyArg_ParseTuple(args, "s", &s);

//多个参数解析: f(1, 2,'strings')
PyArg_ParseTuple(args, "lls", &k, &l, &s);

//组合参数解析:元组+字符串+字符串长度: f((1, 2), 'strings')
PyArg_ParseTuple(args, "(ii)s#", &i, &j, &s, &size);

//可选参数解析:f('strings')
// or f('strings', 'hello') 
// or f('strings', 'hello', 100000)
PyArg_ParseTuple(args, "s|si", &file, &mode, &bufsize);
8.释放资源
/*
说明:
    这是一个宏定义,释放PyObject*对象
    Py_DECREF:比Py_XDECREF较快
    Py_XDECREF:比Py_DECREF较为安全,需要判断PyObject是否为空再去释放
*/
Py_DECREF(PyObject*);
Py_XDECREF(PyObject*);

/*最后调用,与Py_Initialize对应*/
Py_Finalize();

注:

        当使用PyTuple_SetItem(PyObject *p, Py_ssize_t pos, PyObject *o)函数,将对象o插入对象p时,即在组装元组时,只需释放最外层的元组即可,且推荐使用Py_XDECREF更安全。

三、程序示例

 C语言部分

#include 

int main()
{
    Py_Initialize(); //初始化
    if (!Py_IsInitialized())
    {
        return -1; //init python failed
    }
    //相当于在python中的import sys语句。

这个函数是宏,相当于直接运行python语句 PyRun_SimpleString("import sys"); PyRun_SimpleString("sys.path.append('./')");//是将搜索路径设置为当前目录。

PyObject *pmodule = PyImport_ImportModule("hello"); //导入hello.py if (!pmodule) { printf("cannot find hello.py\n"); return -1; } else { printf("PyImport_ImportModule success\n"); } PyObject *pfunc = PyObject_GetAttrString(pmodule, "func1"); //导入func1函数 if (!pfunc) { printf("cannot find func\n"); Py_XDECREF(pmodule); return -1; } else { printf("PyObject_GetAttrString success\n"); } // 向Python传参数是以元组(tuple)的方式传过去的, // 因此我们实际上就是构造一个合适的Python元组就可以了 // 要用到PyTuple_New,Py_BuildValue,PyTuple_SetItem等几个函数 /*这个元组其实只是传参的载体 创建几个元素python函数就是几个参数,这里创建的元组是作为1个参数传递的*/ PyObject *pArgs = PyTuple_New(3); PyObject *pVender = Py_BuildValue("i", 2); //构建参数1 PyObject *pDataID = Py_BuildValue("i", 10001); //构建参数2 PyObject *pyTupleList = PyTuple_New(2); //构建参数3,这里创建的元组是作为c的数组 float arr_f[2]; arr_f[0] = 78; arr_f[1] = 3.41; for (int i = 0; i < 2; i++) { //这里是把c数组构建成python的元组 PyTuple_SetItem(pyTupleList, i, Py_BuildValue("f", arr_f[i])); } //参数入栈 PyTuple_SetItem(pArgs, 0, pVender); PyTuple_SetItem(pArgs, 1, pDataID); PyTuple_SetItem(pArgs, 2, pyTupleList); //调用python脚本函数 PyObject *pResult = PyObject_CallObject(pfunc, pArgs); int a; float b; // PyArg_Parse(pResult, "i", &a); PyArg_ParseTuple(pResult,"if",&a,&b); printf("%d %f\n", a,b); //释放资源 Py_XDECREF(pmodule); Py_XDECREF(pfunc); Py_XDECREF(pArgs); Py_XDECREF(pResult); Py_Finalize(); return 0; }

python部分

import logging

LOG_FORMAT = "[%(asctime)s][%(levelname)s][%(module)s.py:%(lineno)d]---> %(message)s"
DATE_FORMAT = "%Y%m%d %T"
logging.basicConfig(filename="hello.log", level=logging.DEBUG, format=LOG_FORMAT, datefmt=DATE_FORMAT)

ch = logging.StreamHandler()    # 输出到控制台
ch.setLevel(logging.DEBUG)
ch.setFormatter(logging.Formatter(LOG_FORMAT,DATE_FORMAT))
logging.getLogger().addHandler(ch)


def func1(vender,dataid,tuple):
    logging.info("vender = %d, dataid = %d" % (vender,dataid))
    logging.info("type tuple = [%s] tuple = [%s]" % (str(type(tuple)), str(tuple)))
    return (15,5.6)
四、编译
gcc main.c -L/usr/lib/aarch64-linux-gnu -lpython3.6m -o main

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/662203.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-18
下一篇 2022-04-18

发表评论

登录后才能评论

评论列表(0条)

保存