C/Python 之间的调用关系_PHP教程
C/Python 之间的调用关系
由于python有很多功能强大的开源库,c可以借用其中方法,完成更多的功能。
因此C调用python的方法尤其重要。
方法/步骤
-
ubuntu 14.04 linux c
gcc (Ubuntu 4.8.2-19ubuntu1) 4.8.2
Python 2.7.6
-
file 1 [python file]: math_test.py
def add_func(a,b):
return a+b
def sub_func(a,b):
return (a-b)
file 2 [c source file]: c_call_python.c
#include
#include
#include
#include "python2.7/Python.h"
int main(int argc, char** argv)
{
int arg0 = 0,arg1 = 0;
if(argc == 3){
arg0 = atoi(argv[1]);
arg1 = atoi(argv[2]);
}else{
printf("please input 2 args!!\n");
return -1;
}
Py_Initialize();
if ( !Py_IsInitialized())
return -1;
PyRun_SimpleString("import sys");
PyRun_SimpleString("sys.path.append('./')");
PyObject *pModule;
PyObject *pFunction;
PyObject *pArgs;
PyObject *pRetValue;
pModule = PyImport_ImportModule("math_test");
if(!pModule){
printf("import python failed!!\n");
return -1;
}
pFunction = PyObject_GetAttrString(pModule, "add_func");
if(!pFunction){
printf("get python function failed!!!\n");
return -1;
}
pArgs = PyTuple_New(2);
PyTuple_SetItem(pArgs, 0, Py_BuildValue("i", arg0));
PyTuple_SetItem(pArgs, 1, Py_BuildValue("i", arg1));
pRetValue = PyObject_CallObject(pFunction, pArgs);
printf("%d + %d = %ld\n",arg0,arg1,PyInt_AsLong(pRetValue));
Py_DECREF(pModule);
Py_DECREF(pFunction);
Py_DECREF(pArgs);
Py_DECREF(pRetValue);
Py_Finalize();
return 0;
}
- 3
root@linux:~/code# gcc -o c_call_python c_call_python.c -lpython2.7
root@linux:~/code# ./c_call_python 12 15
12 + 15 = 27
Python 扩展中的Py_BuildValue()函数
Py_BuildValue()函数的作用和PyArg_ParseTuple()的作用相反,它是将C类型的数据结构转换成Python对象,该函数的原型: PyObject *Py_BuildValue(char *format, ...) 该函数可以和PyArg_ParseTuple()函数一样识别一系列的格式串,但是输入参数只能是值,而不能是指针。它返回一个Python对象。 和PyArg_ParseTuple()不同的一点是PyArg_ParseTuple()函数它的第一个参数为元组,Py_BuildValue()则不一定会生成一个元组。它生成一个元组仅仅当格式串包含两个或者多个格式单元,如果格式串为空,返回NONE。 在下面的描述中,括号中的项是格式单元返回的Python对象类型,方括号中的项为传递的C的值的类型。 "s" (string) [char *] :将C字符串转换成Python对象,如果C字符串为空,返回NONE。 "s#" (string) [char *, int] :将C字符串和它的长度转换成Python对象,如果C字符串为空指针,长度忽略,返回NONE。 "z" (string orNone) [char *] :作用同"s"。 "z#" (string orNone) [char *, int] :作用同"s#"。 "i" (integer) [int] :将一个C类型的int转换成Python int对象。 "b" (integer) [char] :作用同"i"。 "h" (integer) [short int] :作用同"i"。 "l" (integer) [long int] :将C类型的long转换成Pyhon中的int对象。 "c" (string of length 1) [char] :将C类型的char转换成长度为1的Python字符串对象。 "d" (float) [double] :将C类型的double转换成python中的浮点型对象。 "f" (float) [float] :作用同"d"。 "O&" (object) [converter,anything] :将任何数据类型通过转换函数转换成Python对象,这些数据作为转换函数的参数被调用并且返回一个新的Python对象,如果发生错误返回NULL。 "(items)" (tuple) [matching-items] :将一系列的C值转换成Python元组。 "[items]" (list) [matching-items] :将一系列的C值转换成Python列表。 "{items}" (dictionary) [matching-items] :将一系类的C值转换成Python的字典,每一对连续的C值将转换成一个键值对。
例如: Py_BuildValue("") None Py_BuildValue("i", 123) 123 Py_BuildValue("iii", 123, 456, 789) (123, 456, 789) Py_BuildValue("s", "hello") 'hello' Py_BuildValue("ss", "hello", "world") ('hello', 'world') Py_BuildValue("s#", "hello", 4) 'hell' Py_BuildValue("()") () Py_BuildValue("(i)", 123) (123,) Py_BuildValue("(ii)", 123, 456) (123, 456) Py_BuildValue("(i,i)", 123, 456) (123, 456) Py_BuildValue("[i,i]", 123, 456) [123, 456] Py_BuildValue("{s:i,s:i}","abc", 123, "def", 456) {'abc': 123, 'def': 456} Py_BuildValue("((ii)(ii)) (ii)",1, 2, 3, 4, 5, 6) (((1, 2), (3, 4)), (5, 6))深入浅析 C++ 调用 Python 模块
Python 提供了 C++ 库,使得开发者能很方便地从 C++ 程序中调用 Python 模块。接下来通过本文给大家介绍 C++ 调用 Python 模块的相关知识,需要的朋友参考下吧一般开发过游戏的都知道Lua和C++可以很好的结合在一起,取长补短,把Lua脚本当成类似动态链接库来使用,很好的利用了脚本开发的灵活性。而作为一门流行的通用型脚本语言Python,也是可以做到的。在一个C++应用程序中,我们可以用一组插件来实现一些具有统一接口的功能,一般插件都是使用动态链接库实现,如果插件的变化比较频繁,我们可以使用Python来代替动态链接库形式的插件(堪称文本形式的动态链接库),这样可以方便地根据需求的变化改写脚本代码,而不是必须重新编译链接二进制的动态链接库。灵活性大大的提高了。
作为一种胶水语言,Python 能够很容易地调用 C 、 C++ 等语言,也能够通过其他语言调用 Python 的模块。
Python 提供了 C++ 库,使得开发者能很方便地从 C++ 程序中调用 Python 模块。
具体的文档参考官方指南:
Embedding Python in Another Application
调用方法
1 链接到 Python 调用库
Python 安装目录下已经包含头文件( include 目录)和库文件 ( Windows 下为 python27.lib)。
使用之前需要链接到此库。
2 直接调用 Python 语句
<code class="cpp hljs ">#include "python/Python.h"int main(){Py_Initialize(); ## 初始化PyRun_SimpleString("print 'hello'");Py_Finalize(); ## 释放资源}</code>
登录后复制3 加载 Python 模块并调用函数
~/test 目录下含有 test.py :
<code class="python hljs ">def test_add(a, b):print 'add ', a, ' and ', breturn a+b</code>
登录后复制则可以通过以下代码调用 test_add 函数 :
<code class="cpp hljs ">#include "python/Python.h"#include <iostream>using namespace std;int main(){Py_Initialize(); // 初始化// 将Python工作路径切换到待调用模块所在目录,一定要保证路径名的正确性string path = "~/test";string chdir_cmd = string("sys.path.append(\"") + path + "\")";const char* cstr_cmd = chdir_cmd.c_str();PyRun_SimpleString("import sys");PyRun_SimpleString(cstr_cmd);// 加载模块PyObject* moduleName = PyString_FromString("test"); //模块名,不是文件名PyObject* pModule = PyImport_Import(moduleName);if (!pModule) // 加载模块失败{cout << "[ERROR] Python get module failed." << endl;return 0;}cout << "[INFO] Python get module succeed." << endl;// 加载函数PyObject* pv = PyObject_GetAttrString(pModule, "test_add");if (!pv || !PyCallable_Check(pv)) // 验证是否加载成功{cout << "[ERROR] Can't find funftion (test_add)" << endl;return 0;}cout << "[INFO] Get function (test_add) succeed." << endl;// 设置参数PyObject* args = PyTuple_New(2); // 2个参数PyObject* arg1 = PyInt_FromLong(4); // 参数一设为4PyObject* arg2 = PyInt_FromLong(3); // 参数二设为3PyTuple_SetItem(args, 0, arg1);PyTuple_SetItem(args, 1, arg2);// 调用函数PyObject* pRet = PyObject_CallObject(pv, args);// 获取参数if (pRet) // 验证是否调用成功{long result = PyInt_AsLong(pRet);cout << "result:" << result;}Py_Finalize(); ## 释放资源return 0;}</iostream></code>
登录后复制参数传递
1 C++ 向 Python 传递参数
Python 的参数实际上是元组,因此传参实际上就是构造一个合适的元组。
常用的有两种方法:
使用 PyTuple_New 创建元组, PyTuple_SetItem 设置元组值
<code class="cpp hljs ">PyObject* args = PyTuple_New(3);PyObject* arg1 = Py_BuildValue("i", 100); // 整数参数PyObject* arg2 = Py_BuildValue("f", 3.14); // 浮点数参数PyObject* arg3 = Py_BuildValue("s", "hello"); // 字符串参数PyTuple_SetItem(args, 0, arg1);PyTuple_SetItem(args, 1, arg2);PyTuple_SetItem(args, 2, arg3);</code>
登录后复制直接使用Py_BuildValue构造元组
<code class="cpp hljs ">PyObject* args = Py_BuildValue("ifs", 100, 3.14, "hello");PyObject* args = Py_BuildValue("()"); // 无参函数</code>
登录后复制i, s, f之类的格式字符串可以参考 格式字符串
2 转换 Python 返回值
调用 Python 得到的都是PyObject对象,因此需要使用 Python 提供的库里面的一些函数将返回值转换为 C++ , 例如 PyInt_AsLong,PyFloat_AsDouble, PyString_AsString 等。
还可以使用 PyArg_ParseTuple 函数来将返回值作为元组解析。
PyArg_Parse 也是一个使用很方便的转换函数。
PyArg_ParseTuple 和 PyArg_Parse 都使用 格式字符串
注意事项
需要将 Python 的工作目录切换到模块所在路径 按照模块名加载而不是文件名 模块加载或者函数加载需要验证是否成功,否则可能会引起堆栈错误导致程序崩溃 需要使用 Py_DECREF(PyObject*) 来解除对象的引用(以便Python垃圾回收)

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

热门话题

最近几天,Ice Universe 不断披露有关 Galaxy S25 Ultra 的详细信息,人们普遍认为这款手机将是三星的下一款旗舰智能手机。除此之外,泄密者声称三星只计划升级一款相机

OnLeaks 现在与 Android Headlines 合作,首次展示了 Galaxy S25 Ultra,几天前,他试图从他的 X(以前的 Twitter)粉丝那里筹集到 4,000 美元以上的资金,但失败了。对于上下文,嵌入在 h 下面的渲染图像

除了发布两款新智能手机外,TCL 还发布了一款名为 NXTPAPER 14 的新 Android 平板电脑,其大屏幕尺寸是其卖点之一。 NXTPAPER 14 采用 TCL 标志性品牌哑光液晶面板 3.0 版本

最近几天,Ice Universe 不断披露有关 Galaxy S25 Ultra 的详细信息,人们普遍认为这款手机将是三星的下一款旗舰智能手机。除此之外,泄密者声称三星只计划升级一款相机

Vivo Y300 Pro刚刚全面亮相,它是最薄的中端Android手机之一,配备大电池。准确来说,这款智能手机的厚度仅为 7.69 毫米,但配备了 6,500 mAh 的电池。这与最近推出的容量相同

三星尚未就何时更新其 Fan Edition (FE) 智能手机系列提供任何提示。目前来看,Galaxy S23 FE 仍然是该公司的最新版本,于 2023 年 10 月年初推出。

Redmi Note 14 Pro Plus 现已正式成为去年 Redmi Note 13 Pro Plus 的直接后继产品(亚马逊售价 375 美元)。正如预期的那样,Redmi Note 14 Pro Plus与Redmi Note 14和Redmi Note 14 Pro一起成为Redmi Note 14系列的主角。李

摩托罗拉今年发布了无数设备,尽管其中只有两款是可折叠的。就上下文而言,虽然世界上大多数地区都收到了 Razr 50 和 Razr 50 Ultra,但摩托罗拉在北美提供了 Razr 2024 和 Razr 2
