Python扩展模块的开发

有关python C扩展开发的教程可以参考概述 --- Python 3.12.3 文档。项目已经发布至python官方的pypi里了。具体详情请见AdroitFisherman · PyPI。目前该项目还处在测试阶段。尚有部分模块需要开发和测试。

项目结构

项目结构见下图:

代码展示与说明

以单链表(SingleLinkedList.c)为例。代码如下所示:

SingleLinkedList.h文件

cpp 复制代码
#ifndef SINGLELINKEDLIST_INCLUDED
#define SINGLELINKEDLIST_INCLUDED
typedef PyObject* ElemType;
typedef struct Node
{
    PyObject_HEAD
    ElemType elem;
    struct Node* next;
}LNode;
typedef struct {
    PyObject_HEAD
    LNode* instance;
}List;
static void LNode_destroy(LNode* self)
{
    Py_DECREF(self->elem);
    Py_DECREF(self->next);
    Py_TYPE(self)->tp_free(self);
}
static void List_destroy(List* self)
{
    Py_DECREF(self->instance);
    Py_TYPE(self)->tp_free(self);
}
static PyObject* LNode_new(PyTypeObject* type,PyObject* args)
{
    LNode* self;
    self = (LNode*)type->tp_alloc(type,0);
    if (self==NULL)
    {
        PyErr_SetString(PyExc_Exception, "list node object created failure!");
        return NULL;
    }
    else
    {
        self->elem = NULL;
        self->next = NULL;
        return (PyObject*)self;
    }
}
static PyObject* List_new(PyTypeObject* type, PyObject* args, PyObject* kwds)
{
    List* self;
    self = (List*)type->tp_alloc(type, 0);
    if (self==NULL)
    {
        PyErr_SetString(PyExc_Exception, "list object created failure!");
        return NULL;
    }
    else
    {
        self->instance = NULL;
        return (PyObject*)self;
    }
}
static int LNode_init(LNode* self,PyObject*args,PyObject*kwds)
{
    Py_INCREF(self);
    return 0;
}
static int List_init(List*self,PyObject*args,PyObject*kwds)
{
    Py_INCREF(self);
    return 0;
}
static PyMemberDef LNode_members[] = {
    {"elem",T_OBJECT,offsetof(LNode,elem),0,""},
    {"next",T_OBJECT,offsetof(LNode,next),0,""},
    {NULL}
};
static PyMemberDef List_members[] = {
    {"instance",T_OBJECT,offsetof(List,instance),0,""},
    {NULL}
};
static PyObject* InitList(List* self, PyObject* args, PyObject* kwds)
{
    self->instance = (LNode*)PyMem_MALLOC(sizeof(LNode));
    if (self->instance==NULL)
    {
        Py_RETURN_FALSE;
    }
    else
    {
        self->instance->elem = NULL;
        self->instance->next = NULL;
        Py_RETURN_TRUE;
    }
}
static PyObject* DestroyList(List*self,PyObject*args)
{
    LNode* temp = self->instance;
    while (self->instance!=NULL)
    {
        temp = self->instance;
        self->instance = temp->next;
        PyMem_FREE(temp);
        temp = NULL;
    }
    Py_RETURN_TRUE;
}
static PyObject* ClearList(List*self,PyObject*args)
{
    LNode* temp = self->instance;
    while (self->instance->next!=NULL)
    {
        temp = self->instance->next;
        self->instance->next = temp->next;
        PyMem_FREE(temp);
        temp = NULL;
    }
    Py_RETURN_TRUE;
}
static PyObject* ListEmpty(List*self,PyObject*args)
{
    LNode* temp = self->instance;
    if (temp->next!=NULL)
    {
        Py_RETURN_FALSE;
    }
    else
    {
        Py_RETURN_TRUE;
    }
}
static PyObject* ListLength(List*self,PyObject*args)
{
    LNode* temp = self->instance;
    int counter=0;
    while (temp->next!=NULL)
    {
        counter++;
        temp = temp->next;
    }
    PyObject* result = Py_BuildValue("i",counter);
    Py_INCREF(result);
    return result;
}
static PyObject* GetElem(List*self,PyObject*args)
{
    int index;
    PyObject* result;
    if (PyArg_ParseTuple(args,"i",&index)<0)
    {
        PyErr_SetString(PyExc_Exception, "Args parsed failure!");
        Py_RETURN_NONE;
    }
    else {
        if (index<0||index>=ListLength(self,NULL))
        {
            Py_RETURN_NONE;
        }
        else
        {
            LNode* temp = self->instance->next;
            int counter = 0;
            while (counter<index)
            {
                temp = temp->next;
                counter++;
            }
            result = temp->elem;
            Py_XINCREF(result);
            return result;
        }
    }
}
static PyObject* AddFirst(List*self,PyObject*args)
{
    PyObject* elem;
    if (PyArg_ParseTuple(args,"O",&elem)<0)
    {
        Py_RETURN_FALSE;
    }
    LNode* summon = (LNode*)PyMem_MALLOC(sizeof(LNode));
    if (summon==NULL)
    {
        Py_RETURN_FALSE;
    }
    else
    {
        Py_XINCREF(elem);
        summon->elem = elem;
        summon->next = self->instance->next;
        self->instance->next = summon;
        Py_RETURN_TRUE;
    }
}
static PyObject* AddAfter(List*self,PyObject*args)
{
    PyObject* elem;
    if (PyArg_ParseTuple(args, "O", &elem) < 0)
    {
        Py_RETURN_FALSE;
    }
    LNode* summon = (LNode*)PyMem_MALLOC(sizeof(LNode));
    if (summon == NULL)
    {
        Py_RETURN_FALSE;
    }
    else
    {
        LNode* temp = self->instance;
        while (temp->next!=NULL)
        {
            temp = temp->next;
        }
        Py_XINCREF(elem);
        summon->elem = elem;
        summon->next = temp->next;
        temp->next = summon;
        Py_RETURN_TRUE;
    }
}
static PyObject* ListInsert(List*self,PyObject*args)
{
    int index;
    PyObject* elem;
    if (PyArg_ParseTuple(args, "iO", &index, &elem) < 0)
    {
        PyErr_SetString(PyExc_Exception, "Args parsed failure!");
        Py_RETURN_FALSE;
    }
    else
    {
        if (index<0||index>ListLength(self,NULL))
        {
            Py_RETURN_FALSE;
        }
        else {
            LNode* temp = self->instance;
            LNode* summon = (LNode*)PyMem_MALLOC(sizeof(LNode));
            if (summon==NULL)
            {
                Py_RETURN_FALSE;
            }
            else
            {
                int counter = 0;
                while (counter<index)
                {
                    temp = temp->next;
                    counter++;
                }
                Py_XINCREF(elem);
                summon->elem = elem;
                summon->next = temp->next;
                temp->next = summon;
                Py_RETURN_TRUE;
            }
        }
    }
}
static PyObject* ListDelete(List*self,PyObject*args)
{
    int index;
    if (PyArg_ParseTuple(args, "i", &index) < 0)
    {
        PyErr_SetString(PyExc_Exception, "Args parsed failure!");
        Py_RETURN_FALSE;
    }
    else
    {
        if (index<0||index>=ListLength(self,NULL))
        {
            Py_RETURN_FALSE;
        }
        else
        {
            LNode* temp = self->instance;
            LNode* del;
            int counter = 0;
            while (counter<index)
            {
                temp = temp->next;
                counter++;
            }
            del = temp->next;
            temp->next = del->next;
            PyMem_FREE(del);
            del = NULL;
            Py_RETURN_TRUE;
        }
    }
}
static PyMethodDef List_methods[] = {
    {"init_list",InitList,METH_VARARGS,""},
    {"destroy_list",DestroyList,METH_VARARGS,""},
    {"clear_list",ClearList,METH_VARARGS,""},
    {"list_empty",ListEmpty,METH_VARARGS,""},
    {"list_length",ListLength,METH_VARARGS,""},
    {"get_elem",GetElem,METH_VARARGS,""},
    {"add_first",AddFirst,METH_VARARGS,""},
    {"add_after",AddAfter,METH_VARARGS,""},
    {"list_insert",ListInsert,METH_VARARGS,""},
    {"list_delete",ListDelete,METH_VARARGS,""},
    {NULL}
};
static PyTypeObject LNodeObject = {
    PyVarObject_HEAD_INIT(NULL,0)
    .tp_name = "SingleLinkedList.LNode",
    .tp_new = LNode_new,
    .tp_init = (initproc)LNode_init,
    .tp_dealloc = (destructor)LNode_destroy,
    .tp_basicsize = sizeof(LNode),
    .tp_itemsize = 0,
    .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
    .tp_members = LNode_members
};
static PyTypeObject SingleLinkedListObject = {
    PyVarObject_HEAD_INIT(NULL,0)
    .tp_name="SingleLinkedList.List",
    .tp_new=List_new,
    .tp_init=(initproc)List_init,
    .tp_dealloc=(destructor)List_destroy,
    .tp_basicsize=sizeof(List),
    .tp_itemsize=0,
    .tp_flags=Py_TPFLAGS_BASETYPE|Py_TPFLAGS_DEFAULT,
    .tp_members=List_members,
    .tp_methods=List_methods
};
#endif // SINGLELINKEDLIST_INCLUDED

SingleLinkedList.c文件

cpp 复制代码
#define PY_SIZE_T_CLEAN
#include <python.h>
#include <structmember.h>
#include "SingleLinkedList.h"
static PyModuleDef module = {
    PyModuleDef_HEAD_INIT,
    .m_name="SingleLinkedList",
    .m_size = -1
};
PyMODINIT_FUNC PyInit_SingleLinkedList()
{
    PyObject* m;
    if (PyType_Ready(&LNodeObject)<0)
    {
        return NULL;
    }
    if (PyType_Ready(&SingleLinkedListObject)<0)
    {
        return NULL;
    }
    m = PyModule_Create(&module);
    if (m==NULL)
    {
        return NULL;
    }
    Py_INCREF(&LNodeObject);
    if (PyModule_AddObject(m,"LNode",(PyObject*)&LNodeObject)<0)
    {
        PyErr_SetString(PyExc_Exception, "list object added failure!");
        Py_DECREF(&LNodeObject);
        Py_DECREF(m);
        return NULL;
    }
    Py_INCREF(&SingleLinkedListObject);
    if (PyModule_AddObject(m,"List",(PyObject*)&SingleLinkedListObject)<0)
    {
        PyErr_SetString(PyExc_Exception, "list object added failure!");
        Py_DECREF(&SingleLinkedListObject);
        Py_DECREF(m);
        return NULL;
    }
    return m;
}

代码封装

SingleLinkedList.py

python 复制代码
from AdroitFisherman.SingleLinkedList import List


class ListObject:
    def __init__(self):
        self.__list = List()
        self.__list.init_list()

    def destroy(self):
        self.__list.destroy_list()

    def clear_list(self):
        self.__list.clear_list()

    def list_empty(self):
        return self.__list.list_empty()

    def list_length(self):
        return self.__list.list_length()

    def get_elem(self, index):
        return self.__list.get_elem(index)

    def add_first(self, elem):
        return self.__list.add_first(elem)

    def add_after(self, elem):
        return self.__list.add_after(elem)

    def list_insert(self, index, elem):
        return self.__list.list_insert(index, elem)

    def list_delete(self, index):
        return self.__list.list_delete(index)

    def __del__(self):
        self.__list.destroy_list()

功能描述

该单链表实现了python的数据类型扩展。能够支持不同的python类和数据类型如int、str等的数据存储与处理。由于该项目使用到的C语言语法标准为C99。所以在使用PyTypeObject结构体进行python类信息插槽定义时可以使用结构体变量的特定初始化。同理也可使用结构体的特定初始化对PyModuleDef定义的模板进行定义与声明。

相关推荐
Dontla几秒前
Rust泛型系统类型推导原理(Rust类型推导、泛型类型推导、泛型推导)为什么在某些情况必须手动添加泛型特征约束?(泛型trait约束)
开发语言·算法·rust
XMYX-023 分钟前
Python 操作 Elasticsearch 全指南:从连接到数据查询与处理
python·elasticsearch·jenkins
正义的彬彬侠28 分钟前
sklearn.datasets中make_classification函数
人工智能·python·机器学习·分类·sklearn
belldeep29 分钟前
python:用 sklearn 转换器处理数据
python·机器学习·sklearn
安静的_显眼包O_o31 分钟前
from sklearn.preprocessing import Imputer.处理缺失数据的工具
人工智能·python·sklearn
安静的_显眼包O_o35 分钟前
from sklearn.feature_selection import VarianceThreshold.移除低方差的特征来减少数据集中的特征数量
人工智能·python·sklearn
_可乐无糖1 小时前
pytest中的断言
python·pytest
Neophyte06081 小时前
C++算法练习-day40——617.合并二叉树
开发语言·c++·算法
慕容复之巅1 小时前
基于MATLAB的条形码的识别图像处理报告
开发语言·图像处理·matlab
Wils0nEdwards1 小时前
Leetcode 整数转罗马数字
linux·python·leetcode