1. 程式人生 > >Python C API 使用詳解(二)

Python C API 使用詳解(二)

error 獲取 應該 tro pytho 都是 鍵值 字符 tin

簡介

介紹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;
}

Python C API 使用詳解(二)