日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > python >内容正文

python

扩展Python模块系列(二)----一个简单的例子

發(fā)布時(shí)間:2025/3/15 python 19 豆豆
生活随笔 收集整理的這篇文章主要介紹了 扩展Python模块系列(二)----一个简单的例子 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

?

本節(jié)使用一個(gè)簡(jiǎn)單的例子引出Python C/C++ API的詳細(xì)使用方法。針對(duì)的是CPython的解釋器。

?目標(biāo):創(chuàng)建一個(gè)Python內(nèi)建模塊test,提供一個(gè)功能函數(shù)distance, 計(jì)算空間中兩個(gè)點(diǎn)之間的距離。

可以在Python代碼這樣使用test模塊:

import test s = test.distance((0, 0, 0), (1, 1, 1))

先上代碼:

[test.c]

#include <Python.h> #include <math.h>static PyObject* distance(PyObject* self, PyObject* args) {double x0, y0, z0, x1, y1, z1;if (!PyArg_ParseTuple(args, "(ddd)(ddd)", &x0, &y0, &z0, &x1, &y1, &z1)){return NULL;}return PyFloat_FromDouble(sqrt((x0 - x1) * (x0 - x1) + (y0 - y1) * (y0 - y1) + (z0 - z1) * (z0 - z1))); }static PyMethodDef cformula_methods[] = { { "distance", distance, METH_VARARGS, "Return the 2D Distance of 2 Points." },{ NULL, NULL, 0, NULL }, };PyMODINIT_FUNC inittest(void) {Py_InitModule3("test", cformula_methods, "Common test Written in C."); }

?[Source.cpp]

#include <Python.h>PyMODINIT_FUNC inittest();int main() {//PyImport_AppendInittab("test", inittest); Py_Initialize(); inittest(); PyRun_SimpleString("import test");PyRun_SimpleString("s = test.distance((0, 0, 0), (1, 1, 1))");PyRun_SimpleString("print s");return 0; }

編譯運(yùn)行后,結(jié)果如下:

如果希望將test模塊打包為一個(gè)動(dòng)態(tài)鏈接庫(kù),供其他Python程序使用,即打包為test.pyd,在其他Python程序中可以直接import test,就和正常的Python內(nèi)建模塊一樣。

步驟如下:

1) 在test.c同級(jí)目錄下,新建一個(gè)python文件setup.py

2)setup.py:

from distutils.core import setup, Extension setup(ext_modules=[Extension('test', sources = ['test.c'])])

3) 執(zhí)行python命令: python setup.py build

?這種情況是因?yàn)闆]有指定C的編譯器,本文使用VS2015提供的編譯器,所以首先執(zhí)行:SET VS90COMNTOOLS=%VS140COMNTOOLS%

會(huì)在該目錄下發(fā)現(xiàn)build/lib.win32-2.7中有一個(gè)test.pyd,這就是編譯后的動(dòng)態(tài)庫(kù),可以直接import

?

?實(shí)現(xiàn)細(xì)節(jié):

1. 任何擴(kuò)展Python模塊的C程序,一般只需要包含<Python.h>頭文件即可,文檔中這樣描述:

All function, type and macro definitions needed to use the Python/C API are included in your code by the following line:

#include "Python.h"

在包含了Python.h之后,隱含地會(huì)自動(dòng)包含C語(yǔ)言的標(biāo)準(zhǔn)頭文件<stdio.h>, <string.h>, <errno.h>, <limits.h>, <assert.h> and <stdlib.h>

2. 本質(zhì)上Python C API提供了對(duì)C函數(shù)的wrapper。假設(shè)有一個(gè)現(xiàn)成的C函數(shù), int add(int a, int b), 想把它實(shí)現(xiàn)在Python的模塊里,需要實(shí)現(xiàn)一個(gè)wrapper函數(shù) static PyObject* addAB(PyObject* self, PyObject* args), 將args解析為兩個(gè)整數(shù)a、b,然后調(diào)用add(a,b),將返回值打包為一個(gè)Python整型對(duì)象返回。

?

static PyObject* distance(PyObject* self, PyObject* args)

?

函數(shù)一定要聲明為static,將其限定在此文件范圍;參數(shù)self是Python內(nèi)部使用的,遵循范式即可;參數(shù)args是函數(shù)的參數(shù)列表,是一個(gè)tuple。

PyArg_ParseTuple(args, "(ddd)(ddd)", &x0, &y0, &z0, &x1, &y1, &z1)

此函數(shù)將參數(shù)列表args解析為兩個(gè)tuple, 每個(gè)tuple是三個(gè)double類型的元素。如果參數(shù)列表不符合"(ddd)(ddd)"這種形式,直接返回NULL。

PyFloat_FromDouble

此函數(shù)將一個(gè)C原生的double,封裝Python 的PyFloatObject。

3. 定義該模塊對(duì)外提供的函數(shù)接口

static PyMethodDef cformula_methods[]

在此數(shù)據(jù)結(jié)構(gòu)中定義模塊test對(duì)外提供的函數(shù)接口,第一個(gè)參數(shù)"distance"是Python內(nèi)部記錄的,就是test.distance調(diào)用時(shí),python查找的函數(shù)名;第二個(gè)參數(shù)distance是函數(shù)具體實(shí)現(xiàn),本質(zhì)是一個(gè)函數(shù)指針;第三個(gè)參數(shù)是METH_VARARGS告訴Python此函數(shù)一個(gè)典型的PyCFunction,參數(shù)為兩個(gè)PyOBject*,參數(shù)2使用PyArg_ParseTuple來(lái)解析;最后一個(gè)是函數(shù)說(shuō)明。

4.定義模塊初始化函數(shù)

PyMODINIT_FUNC inittest(void) {Py_InitModule3("test", cformula_methods, "Common test Written in C."); }

函數(shù)inittest必須這樣定義,如果模塊名為example,那么模塊初始化函數(shù)為initexample。宏定義PyMODINIT_FUNC定義如下:

# if defined(__cplusplus) # define PyMODINIT_FUNC extern "C" void # else /* __cplusplus */ # define PyMODINIT_FUNC void # endif /* __cplusplus */

針對(duì)cpp的實(shí)現(xiàn)加了修飾extern "C"。

Py_InitModule3創(chuàng)建模塊test, 當(dāng)import test時(shí),Python解釋器會(huì)找到inittest創(chuàng)建的模塊test。

5. 測(cè)試代碼Source.cpp

在Python虛擬機(jī)環(huán)境初始化?Py_Initialize()之后,調(diào)用inittest(),則會(huì)創(chuàng)建新模塊test。

如果希望在import test時(shí)才初始化模塊test,那么在Py_Initialize()之前調(diào)用PyImport_AppendInittab("test", inittest); 然后再注釋掉initest()。

PyImport_AppendInittab:Add a single module to the existing table of built-in modules.The new module can be imported by the namename, and uses the function?initfunc?as the initialization function called on the first attempted import. This should be called before?Py_Initialize().

?

本節(jié)通過(guò)一個(gè)簡(jiǎn)單的例子來(lái)展示了如何用C語(yǔ)言擴(kuò)展Python模塊,并簡(jiǎn)單解釋了用到的Python C/C++ API。在下一節(jié)中,將更加深入地了解Python C/C++ API,以及在寫擴(kuò)展程序時(shí),會(huì)遇到的坑,比如:異常處理、引用計(jì)數(shù)等等。

?

轉(zhuǎn)載于:https://www.cnblogs.com/jianmu/p/7345716.html

創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來(lái)咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)

總結(jié)

以上是生活随笔為你收集整理的扩展Python模块系列(二)----一个简单的例子的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。