Python C API 使用详解(二)

发布时间:2019-09-07 08:11:19编辑:auto阅读(1317)

    简介

    介绍Python C API中的列表、元组、字典的使用,详细的进行了API中方法的介绍。

    Python List API

    List API 简单介绍

    int PyList_Check(PyObject *p) 判断是否是一个Python List(列表)

    PyObject* PyList_New(Py_ssize_t len) 创建一个列表

    Py_ssize_t PyList_Size(PyObject *list) 获取列表元素的个数 len(list)

    Py_ssize_t PyList_GET_SIZE(PyObject *list) 和PyList_Size 一样,但是就是没有错误检查

    PyObject PyList_GetItem(PyObject list, Py_ssize_t index) 从列表里面获取一个元素,计数器不会加1

    PyObject PyList_GET_ITEM(PyObject list, Py_ssize_t i) 和PyList_GetItem一样,但是就是没有错误检查

    int PyList_SetItem(PyObject list, Py_ssize_t index, PyObject item) 设置别表指定位置的值,下标的所在的位置必须是有值的,并且是有效的

    void PyList_SET_ITEM(PyObject list, Py_ssize_t i, PyObject o) 和PyList_SetItem一样,但是就是没有错误检查

    int PyList_Insert(PyObject list, Py_ssize_t index, PyObject item) 在列表指定位置插入值 list.insert(index, item)

    int PyList_Append(PyObject list, PyObject item) 在列表尾部追加值 list.append(item)

    PyObject PyList_GetSlice(PyObject list, Py_ssize_t low, Py_ssize_t high) 获取列表里面一段切片数据,一段指定范围的数据 list[low:higt]

    int PyList_SetSlice(PyObject list, Py_ssize_t low, Py_ssize_t high, PyObject itemlist) 设置列表分片数据,指定列表范围的数据 list[low:higt] = itemlist

    int PyList_Sort(PyObject *list) 对列表数据进行排序 list.sort()

    int PyList_Reverse(PyObject *list) 把列表里面的所有数据反转 list.reverse()

    PyObject PyList_AsTuple(PyObject list) 将Python列表转为Python元组 tuple(list)

    实例

    注意事项: 不限制大小的Python列表对象,应该用Append初始化数据

    设置大小的Python列表对象,应该用SetItem初始化数据, 如果用Append的话,会出现" 段错误 (核心已转储) "的情况

    头文件

    //
    // Created by lanyulei on 18-9-3.
    //
    
    #ifndef PRINT_DEMO1_PYLIST_H
    #define PRINT_DEMO1_PYLIST_H
    
    #include <Python.h>
    #include "print.h"
    
    // 创建一个固定大小的列表
    void ListNumber();
    
    // 创建一个可以无限扩展的列表
    void ListExpansion();
    
    #endif //PRINT_DEMO1_PYLIST_H

    源文件

    //
    // Created by lanyulei on 18-9-3.
    //
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include "pyList.h"
    
    // 有长短限制的列表
    void ListNumber() {
        PyObject* pyList = PyList_New(3);    // 创建一个大小为3的列表
    
        PyObject* pyId = Py_BuildValue("i", 123);   // 创建Python 整型对象
        PyList_SetItem(pyList, 0, pyId);   // 将Python整型对象插入到Python列表对象中
    
        PyObject* pyName = Py_BuildValue("s", "lanyulei");   // 创建一个字符串python对象
        PyList_SetItem(pyList, 1, pyName);   // 插入到Python列表对象里面去
    
        PyObject* pyFloat = Py_BuildValue("f", 23.98f);   // 创建一个浮点类型的Python对象
        PyList_SetItem(pyList, 2, pyFloat);   // 将其插入到Python列表对象中
    
        int listLength = PyList_Size(pyList);   // 获取列表的长度
        printf("列表长度: %d\n", listLength);
    
        print_pyobject(pyList);    // 打印列表数据
        PyObject* pyName2 = Py_BuildValue("s", "LanYuLei");  // 创建一个字符串python对象
        PyList_Insert(pyList, 1, pyName2);   // 在下标为1的位置插入一条数据
    
        print_pyobject(pyList);    // 打印列表数据
    
        printf("------------sort-------------\n");
        PyList_Sort(pyList);    // 对列表进行排序
        print_pyobject(pyList);    // 打印列表数据
    
        printf("---------------reverse--------------\n");
        PyList_Reverse(pyList);    // 反转列表数据
        print_pyobject(pyList);    // 打印列表数据
    
        printf("----------------slice----------------\n");
        PyObject* pySlice = PyList_GetSlice(pyList, 1, 3);   // 获取分片数据
        print_pyobject(pySlice);    // 打印分片数据
    
    }
    
    // 没有大小限制的列表
    void ListExpansion(){
        PyObject* pyList = PyList_New(0);    // 创建一个没有大小限制的列表,所以参数为 0
    
        PyObject* pyId = Py_BuildValue("i", 123);   // 创建Python 整型对象
        PyList_Append(pyList, pyId);   // 将Python整型对象追加到Python列表对象中
    
        PyObject* pyName = Py_BuildValue("s", "lanyulei");   // 创建一个字符串python对象
        PyList_Append(pyList, pyName);   // 追加到Python列表对象里面去
    
        PyObject* pyFloat = Py_BuildValue("f", 23.98f);   // 创建一个浮点类型的Python对象
        PyList_Append(pyList, pyFloat);   // 将其追加到Python列表对象中
    
        print_pyobject(pyList);
    
        PyObject* py_data = PyList_GetItem(pyList, 0);   // 获取下标为0的数据
        print_pyobject(py_data);
    }

    Python Tuple API

    Tuple API 简单介绍

    int PyTuple_Check(PyObject *p) 判断是否是一个元组对象

    PyObject* PyTuple_New(Py_ssize_t len) 创建一个Python元组对象,注意元组创建是必须设置长度的,如果设置长度为0,则这个元组对象是一个空的元组

    Py_ssize_t PyTuple_Size(PyObject *p) 获取元组的长度,即元组的大小

    Py_ssize_t PyTuple_GET_SIZE(PyObject *p) 和PyTuple_Size一样,只不过这个方法没有错误检查的机制

    PyObject PyTuple_GetItem(PyObject p, Py_ssize_t pos) 获取元组内指定下标的值

    PyObject PyTuple_GET_ITEM(PyObject p, Py_ssize_t pos) 和PyTuple_GetItem一样,只不过这个方法没有错误检查的机制

    PyObject PyTuple_GetSlice(PyObject p, Py_ssize_t low, Py_ssize_t high) 获取分片数据 p[lwo, higt]

    int PyTuple_SetItem(PyObject p, Py_ssize_t pos, PyObject o) 设置元组指定下标的值

    void PyTuple_SET_ITEM(PyObject p, Py_ssize_t pos, PyObject o) 和PyTuple_SetItem一样,只不过这个方法没有错误检查的机制

    int _PyTuple_Resize(PyObject **p, Py_ssize_t newsize) 改变元组的大小

    实例

    头文件

    //
    // Created by lanyulei on 18-9-4.
    //
    
    #ifndef PRINT_DEMO1_PYTUPLE_H
    #define PRINT_DEMO1_PYTUPLE_H
    
    #include <Python.h>
    #include <string.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include "print.h"
    
    // 元组的使用
    void test_tuple();
    
    #endif //PRINT_DEMO1_PYTUPLE_H

    源文件

    //
    // Created by lanyulei on 18-9-4.
    //
    
    #include "pyTuple.h"
    
    void test_tuple(){
        PyObject* pyTuple = PyTuple_New(3);   // 创建一个元组
    
        PyObject* pyId = Py_BuildValue("i", 1);   // 创建一个Python整型对象
        PyTuple_SetItem(pyTuple, 0, pyId);   // 向指定的下标传递数据
    
        PyObject* pyString = Py_BuildValue("s", "lanyulei");   // 创建一个Python字符串对象
        PyTuple_SetItem(pyTuple, 1, pyString);
    
        PyObject* pyFloat = Py_BuildValue("f", 165.46f);    // 创建一个Python浮点对象
        PyTuple_SetItem(pyTuple, 2, pyFloat);
    
        int tupleLength = PyTuple_Size(pyTuple);
        printf("pyTuple size: %d\n", tupleLength);
        print_pyobject(pyTuple);
    
        printf("----------------------PyTuple_GetItem--------------------------\n");
        PyObject* pyData = PyTuple_GetItem(pyTuple, 0);   // 获取元组指定下标的数据
        print_pyobject(pyData);
    
        printf("------------------------遍历元组--------------------------\n");
        // 遍历元组数据
        for (int i = 0; i < PyTuple_Size(pyTuple); i++){
            PyObject* pyData = PyTuple_GetItem(pyTuple, i);
            print_pyobject(pyData);
        }
    
        printf("------------------------获取分片数据--------------------------\n");
        PyObject* pySlice = PyTuple_GetSlice(pyTuple, 1, PyTuple_Size(pyTuple));   // 获取切片数据
        print_pyobject(pySlice);
    
        printf("------------------------修改元组长度--------------------------\n");
        printf("原始长度: %d\n", tupleLength);
        _PyTuple_Resize(&pyTuple, 5);   // 修改元组长度,第一个参数是一个指针
        printf("resize tuple length: %ld\n", PyTuple_Size(pyTuple));
    }

    Python Dict API

    Dict API 简单介绍

    int PyDict_Check(PyObject *p) 判断对象是不是一个字典

    PyObject* PyDict_New() 创建一个Python对象

    void PyDict_Clear(PyObject *p) 清空Python对象的数据

    int PyDict_Contains(PyObject p, PyObject key) 判断字典内是否存在一个键值数据

    PyObject PyDict_Copy(PyObject p) 拷贝一个字典的数据,产生一个新的Python字典对象

    int PyDict_SetItem(PyObject p, PyObject key, PyObject *val) 给Python字典对象设置新的键值数据

    int PyDict_SetItemString(PyObject p, const char key, PyObject *val) 和PyDict_SetItem类似,只不过键是C语言char数据类型的数据

    int PyDict_DelItem(PyObject p, PyObject key) 删除Python键值数据

    int PyDict_DelItemString(PyObject p, const char key) 和PyDict_DelItem类似,只不过键是C语言char数据类型的数据

    PyObject PyDict_GetItem(PyObject p, PyObject *key) 获取Python字典对象的键的值

    PyObject PyDict_GetItemWithError(PyObject p, PyObject *key) 和PyDict_GetItem一样,只不过返回上下文的错误信息

    PyObject PyDict_GetItemString(PyObject p, const char *key) 和PyDict_GetItem一样,只不过键值C语言中char数据类型的数据

    PyObject PyDict_SetDefault(PyObject p, PyObject key, PyObject default) 设置Python字典对象的默认值,当获取的Key不存在的时候则返回当前的默认数据 dict.setdefault()

    PyObject PyDict_Items(PyObject p) 返回一个Python字典对象所有数据的PyListObject, dict.items()

    PyObject PyDict_Keys(PyObject p) 返回一个Python字典对象的所有的Key数据 dict.keys()

    PyObject PyDict_Values(PyObject p) 返回一个Python字典对象的所有Value数据 dict.values()

    Py_ssize_t PyDict_Size(PyObject *p) 获取Python字典的大小 len(dict)

    int PyDict_Next(PyObject p, Py_ssize_t ppos, PyObject pkey, PyObject pvalue) 遍历获取Python字典对象的所有数据, 下面是官方提供的例子

    PyObject *key, *value;
    Py_ssize_t pos = 0;   // 初始值必须为0, 表示遍历所有Python字典对象数据
    
    while (PyDict_Next(self->dict, &pos, &key, &value)) {
        /* do something interesting with the values... */
        ...
    }
    
    PyObject *key, *value;
    Py_ssize_t pos = 0;
    
    while (PyDict_Next(self->dict, &pos, &key, &value)) {
        long i = PyLong_AsLong(value);
        if (i == -1 && PyErr_Occurred()) {
            return -1;
        }
        PyObject *o = PyLong_FromLong(i + 1);
        if (o == NULL)
            return -1;
        if (PyDict_SetItem(self->dict, key, o) < 0) {
            Py_DECREF(o);
            return -1;
        }
        Py_DECREF(o);
    }
    

    int PyDict_Merge(PyObject a, PyObject b, int override) 将b字典内的数据,加入到a字典中去,override表示是否覆盖数据,如果override为true则覆盖数据,反之亦然

    int PyDict_Update(PyObject a, PyObject b) 把b字典中的数据加入到a字典中,如果a和b出现相同的key,则b直接更新a中key对应的值

    实例

    头文件

    //
    // Created by lanyulei on 18-9-5.
    //
    
    #ifndef PRINT_DEMO1_PYDCIT_H
    #define PRINT_DEMO1_PYDCIT_H
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <Python.h>
    #include "print.h"
    
    // 字典练习
    void test_dict();
    
    #endif //PRINT_DEMO1_PYDCIT_H

    源文件

    //
    // Created by lanyulei on 18-9-5.
    //
    
    #include "pyDcit.h"
    
    void test_dict()
    {
        //创建dict
        PyObject* py_dict_1 = PyDict_New();
    
        //检查PyObject是不是一个字典
        int ret = PyDict_Check(py_dict_1);
        if (ret)
        {
            printf("is dict\n");
        }
        else
        {
            printf("is not dict\n");
        }
    
        PyObject *py_key_account_id = Py_BuildValue("s", "account_id");
        PyObject *py_value_account_id = Py_BuildValue("i", 1238);
        //向dict添加一个key-value
        PyDict_SetItem(py_dict_1, py_key_account_id, py_value_account_id);
    
        PyObject *py_value_account_name = Py_BuildValue("s", "mono");
        PyDict_SetItemString(py_dict_1, "account_name", py_value_account_name);
    
        PyObject *py_key1 = Py_BuildValue("i", 1);
        PyObject *py_key1_value = Py_BuildValue("i", 2399);
        PyDict_SetItem(py_dict_1, py_key1, py_key1_value);
    
        //获取字典的大小
        int dict_len = PyDict_Size(py_dict_1);
        printf("dict_len=%d\n", dict_len);
    
        print_pyobject(py_dict_1);
    
        //从字典删除一个key
        PyDict_DelItem(py_dict_1, py_key_account_id);
    
        printf("del item: py_key_account_id--------------------------\n");
        print_pyobject(py_dict_1);
    
        //删除一个不存在的key
        PyObject *py_not_existing_key = Py_BuildValue("s", "name");
        PyDict_DelItem(py_dict_1, py_not_existing_key);
    
        printf("del item: py_not_existing_key------------------\n");
        print_pyobject(py_dict_1);
    
        //-------------------------------------------------------
        //PyDict_DelItemString(py_dict_1, "account_name");
    
        //printf("del item: account_name -----------------\n");
        //print_pyobject(py_dict_1);
    
        PyObject *py_key_account_name = Py_BuildValue("s", "account_name");
        //从字典中获取一个key-value
        PyObject *py_value1 = PyDict_GetItem(py_dict_1, py_key_account_name);
        printf("get item: account_name-----------------------\n");
        print_pyobject(py_value1);
    
        printf("\n");
        //从字典中获取一个key-value
        PyObject *py_value2 = PyDict_GetItemString(py_dict_1, "account_name");
        printf("get item string: account_name -------------------\n");
        print_pyobject(py_value2);
        printf("\n");
    
        //-----------------------------------------------------------
        //从字典中获取所有key-value对
        PyObject *py_items = PyDict_Items(py_dict_1);
        printf("get items --------------------------\n");
        print_pyobject(py_items);
        printf("\n");
    
        //--------------------------------------
        //从字典中获取所有key
        PyObject *py_keys = PyDict_Keys(py_dict_1);
        printf("get keys -------------------------\n");
        print_pyobject(py_keys);
        printf("\n");
    
        //------------------------------------------------
        //从字典获取所有值
        PyObject *py_values = PyDict_Values(py_dict_1);
        printf("get values -----------------------\n");
        print_pyobject(py_values);
        printf("\n");
    
        //------------------------------------------------------
        //遍历字典
        PyObject *key, *value;
        Py_ssize_t pos = 0;
    
        printf("dict next -------------------\n");
        while (PyDict_Next(py_dict_1, &pos, &key, &value))
        {
            print_pyobject(key);
            printf("=");
            print_pyobject(value);
            printf("\n");
        }
    
        //---------------------------------------------
        PyObject *py_dict_2 = PyDict_New();
    
        PyObject *py_key21 = Py_BuildValue("i", 101);
        PyObject *py_key21_value = Py_BuildValue("i", 60000);
        PyDict_SetItem(py_dict_2, py_key21, py_key21_value);
    
        PyObject *py_value_level = Py_BuildValue("i", 30);
        PyDict_SetItemString(py_dict_2, "account_level", py_value_level);
    
        PyObject *py_value_account_name2 = Py_BuildValue("s", "myname");
        PyDict_SetItemString(py_dict_2, "account_name", py_value_account_name2);
    
        printf("dict_2 items --------------------\n");
        print_pyobject(py_dict_2);
    
        //把py_dict_2的所有数据添加到py_dict_1
        PyDict_Merge(py_dict_1, py_dict_2, 0);
    
        printf("dict merge: override=0, -----------------\n");
        print_pyobject(py_dict_1);
    
        //----------------------------------------
        PyObject *py_dict_3 = PyDict_New();
    
        PyObject *py_value_score = Py_BuildValue("i", 10000);
        PyDict_SetItemString(py_dict_3, "account_score", py_value_score);
    
        PyObject *py_value_account_name3 = Py_BuildValue("s", "sujin");
        PyDict_SetItemString(py_dict_3, "account_name", py_value_account_name3);
    
        //将py_dict_3的所有数据添加到py_dict_1, 这个api相当于PyDict_Merge第三个参数为1的情况.
        PyDict_Update(py_dict_1, py_dict_3);
        printf("dict update ----------------------\n");
        print_pyobject(py_dict_1);
    
        //---------------------------------------------
        const char *check_key = "account_name";
        PyObject *py_check_key = Py_BuildValue("s", check_key);
    
        //在字典中检查是否存在这个key
        ret = PyDict_Contains(py_dict_3, py_check_key);
        if (ret)
        {
            printf("has key: %s\n", check_key);
        }
        else
        {
            printf("no key: %s\n", check_key);
        }
    
        //-------------------------------------------------
        //清空字典的所有数据
        PyDict_Clear(py_dict_3);
    
        printf("dict clear ---------------------\n");
        print_pyobject(py_dict_3);
    }

    根据数据类型打印数据的方法

    头文件

    //
    // Created by lanyulei on 18-9-1.
    //
    
    #ifndef PRINT_DEMO1_PRINT_H
    #define PRINT_DEMO1_PRINT_H
    
    #include <Python.h>
    
    void print_pyobject(PyObject *py_obj);
    
    #endif //PRINT_DEMO1_PRINT_H

    源文件

    //
    // Created by lanyulei on 18-9-1.
    //
    
    #include "print.h"
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    
    // Python 中的浮点类型, 都是double
    
    void print_pyobject(PyObject *py_obj){
    
        if (py_obj == NULL){
            printf("NULL");
            return;
        }
    
        if (PyInt_Check(py_obj)){
            // int
            int ival = PyInt_AsLong(py_obj);
            printf("我是整型,ival = %d\n", ival);
        } else if (PyLong_Check(py_obj)){
            // long
            long long lval = PyLong_AsLongLong(py_obj);
            printf("我是长整型,lval = %lld\n", lval);
        } else if (PyFloat_Check(py_obj)){
            // float/double
            double fval = PyFloat_AS_DOUBLE(py_obj);
            printf("我是浮点类型,fval = %lf\n", fval);
        } else if (PyBool_Check(py_obj)){
            // bool
            int bval = PyInt_AsLong(py_obj);
            if (bval == 1){
                printf("我是布尔类型,bval = true\n");
            }else {
                printf("我是布尔类型,bval = false\n");
            }
        } else if (PyString_Check(py_obj)){
            // 不包含中文的字符串
            char *str = PyString_AsString(py_obj);
            printf("我是不包含中文的字符串,str = %s\n", str);
        } else if (PyUnicode_Check(py_obj)){
            // unicode 含有中文的字符串
            // 首先将unicode转成utf-8
            PyObject *py_utf8 = PyUnicode_AsUTF8String(py_obj);
            char *ustr = PyString_AsString(py_utf8);
            printf("我是unicode,ustr = %s\n", ustr);
        } else if (PyList_Check(py_obj)){
            // Python list
            printf("我是列表,");
            printf("[\n");
            for (int i = 0;i < PyList_Size(py_obj); i++){
                PyObject *py_data = PyList_GetItem(py_obj, i);
                print_pyobject(py_data);
            }
            printf("]\n");
        } else if (PyTuple_Check(py_obj)){
            // Python tuple
            printf("我是元组,");
            printf("(\n");
            for (int i = 0;i < PyTuple_Size(py_obj); i++){
                PyObject *py_data = PyTuple_GetItem(py_obj, i);
                print_pyobject(py_data);
            }
            printf(")\n");
        } else if (PyDict_Check(py_obj)){
            // Python dict
            PyObject *key, *value;
            Py_ssize_t pos = 0;
    
            printf("我是字典,");
            printf("{\n");
            while (PyDict_Next(py_obj, &pos, &key, &value)) {
                print_pyobject(key);
                printf("=");
                print_pyobject(value);
            }
            printf("}\n");
        }
    }

    main函数

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    int main() {
    
        // 初始化Python虚拟机
        Py_Initialize();
        // 判断Python虚拟机是否成功
        if (Py_IsInitialized() == 0){
            printf("fal to initialize Python\n");
            return -1;
        }
    
        printf("server start\n");
    
        // 退出Python虚拟机
        Py_Finalize();
        return 0;
    }

关键字