Python扩展模块的开发

server/2024/9/23 21:21:24/

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

项目结构

        项目结构见下图:

代码展示与说明

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

        SingleLinkedList.h文件

#ifndef SINGLELINKEDLIST_INCLUDED
#define SINGLELINKEDLIST_INCLUDED
typedef PyObject* ElemType;
typedef struct Node
{PyObject_HEADElemType elem;struct Node* next;
}LNode;
typedef struct {PyObject_HEADLNode* 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文件

#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 Listclass 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定义的模板进行定义与声明。


http://www.ppmy.cn/server/36865.html

相关文章

数据库中视图的知识点

视图&#xff08;子查询&#xff09;&#xff1a;是从一个或多个表导出的虚拟的表&#xff0c;其内容由查询定义。具有普通表的结构&#xff0c;但是不实现数据存储。对视图的修改&#xff1a;单表视图一般用于查询和修改&#xff0c;会改变基本表的数据&#xff0c;多表视图一…

Qt5 框架学习及应用 — 对象树

Qt 对象树 对象树概念Qt为什么使用对象树 &#xff1f;将对象挂到对象树上 对象树概念 对象树&#xff1a;对于树的概念&#xff0c;相信许多学过数据结构的同学应该都不会陌生。在学习数据结构的时候我们所接触的什么二叉树、多叉树、哈夫曼树、AVL树、再到红黑树、B/B树………

《深入理解kafka-核心设计与实践原理》第四章:主题和分区

第四章&#xff1a;主题和分区 4.1 主题管理 4.1.1 创建主题 4.2 KafkaAdminClient 4.3 分区管理 4.3.1 优先副本的选举 4.3.2 分区重分配(Partition Reassignment) 4.3.3 复制限流 4.3.4 修改副本因子 4.4 分区和性能的考量因素 第四章&#xff1a;主题和分区 4.1 主题管理 …

C++ Primer 总结索引 | 第十四章:重载运算与类型转换

1、C语言定义了 大量运算符 以及 内置类型的自动转换规则 当运算符 被用于 类类型的对象时&#xff0c;C语言允许我们 为其指定新的含义&#xff1b;也能自定义类类型之间的转换规则 例&#xff1a;可以通过下述形式输出两个Sales item的和&#xff1a; cout << item1 …

Python专题:二、Python小游戏,体验Python的魅力

希望先通过一个小的游戏让大家先对Python感兴趣&#xff0c;兴趣是最好的老师。 小游戏的运行结果&#xff1a; 1、在sublime编辑器里面写如下代码&#xff1a; import randomnum random.randint(1, 100) # 获得一个随机数 is_done False # 是否猜中的标记 count 0 # 玩…

FSC森林认证是什么?

FSC森林认证&#xff0c;又称木材认证&#xff0c;是一种运用市场机制来促进森林可持续经营&#xff0c;实现生态、社会和经济目标的工具。FSC森林认证包括森林经营认证&#xff08;Forest Management, FM&#xff09;和产销监管链认证&#xff08;Chain of Custody, COC&#…

Offline:IQL

ICLR 2022 Poster Intro 部分离线强化学习的对价值函数采用的是最小化均方bellman误差。而其中误差源自单步的TD误差。TD误差中对target Q的计算需要选取一个max的动作&#xff0c;这就容易导致采取了OOD的数据。因此&#xff0c;IQL取消max,&#xff0c;通过一个期望回归算子…

Linux进程通信-信号

信号概念 信号是 Linux 进程间通信的最古老的方式之一&#xff0c;是事件发生时对进程的通知机制&#xff0c;有时也称之为软件中断&#xff0c;它是在软件层次上对中断机制的一种模拟&#xff0c;是一种异步通信的方式。信号 可以导致一个正在运行的进程被另一个正在运行的异…