Chinaunix首页 | 论坛 | 博客
  • 博客访问: 17742
  • 博文数量: 4
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 10
  • 用 户 组: 普通用户
  • 注册时间: 2014-10-31 14:23
文章分类
文章存档

2016年(4)

我的朋友
最近访客

分类: Android平台

2016-09-20 20:36:13

原文地址:C/Python 之间的调用关系 作者:iibull

由于python有很多功能强大的开源库,c可以借用其中方法,完成更多的功能。

因此C调用python的方法尤其重要。

方法/步骤

  1. ubuntu 14.04 linux c

    gcc (Ubuntu 4.8.2-19ubuntu1) 4.8.2

    Python 2.7.6

  2. 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. 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 or None) [char *] :作用同"s"。
            "z#" (string or None) [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 语句

    #include "python/Python.h"
    int main()
    {
    Py_Initialize(); ## 初始化
    PyRun_SimpleString("print 'hello'");
    Py_Finalize(); ## 释放资源
    }
    

    3 加载 Python 模块并调用函数

    ~/test 目录下含有 test.py :

    def test_add(a, b):
    print 'add ', a, ' and ', b
    return a+b

    则可以通过以下代码调用 test_add 函数 :

    #include "python/Python.h"
    #include 
    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); // 参数一设为4
    PyObject* arg2 = PyInt_FromLong(3); // 参数二设为3
    PyTuple_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;
    }
    

    参数传递

    1 C++ 向 Python 传递参数

    Python 的参数实际上是元组,因此传参实际上就是构造一个合适的元组。

    常用的有两种方法:

    使用 PyTuple_New 创建元组, PyTuple_SetItem 设置元组值

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

    直接使用Py_BuildValue构造元组

    PyObject* args = Py_BuildValue("ifs", 100, 3.14, "hello");
    PyObject* args = Py_BuildValue("()"); // 无参函数

    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垃圾回收)

阅读(2117) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~