iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >再探C/C++扩展Python
  • 555
分享到

再探C/C++扩展Python

再探Python 2023-01-31 05:01:44 555人浏览 安东尼
摘要

    上篇博文是初用C/C++扩展python,只是简单的举个例子,有兴趣的可以去上篇博文里看看那个例子的代码,代码如下:#include<Python.h> static PyObject *pr_isprime(PyObj

    上篇博文是初用C/C++扩展python,只是简单的举个例子,有兴趣的可以去上篇博文里看看那个例子的代码,代码如下:

#include<Python.h>
static PyObject *pr_isprime(PyObject *self,PyObject *args){
    int n,num;
    if(!PyArg_ParseTuple(args,"i",&num))
        return NULL;
    if(num<1){
        return Py_BuildValue("i",0);
    }
    n=num-1;
    while(n>1){
        if(num%n==0)
            return Py_BuildValue("i",0);
            n--;
    }
    return Py_BuildValue("i",1);
}
 
static PyMethodDef PrMethods[]={
    {"isPrime",pr_isprime,METH_VARARGS,"check if an input numbe is prime or not."},
    {NULL,NULL,0,NULL}
};
 
void initpr(void){
    (void) Py_InitModule("pr",PrMethods);
}

这两天花时间简单的研究了一下那个代码,其中最关键的是Python.h这头文件,我们可以看看这个头文件的源代码。(用的是Python2.7.12,ubuntu16.04 LTS,Python.h在/usr/include/python2.7/里)

为了节省篇幅,特意将源代码中注释给删掉,不便之处敬请谅解。

#ifndef Py_PYTHON_H
#define Py_PYTHON_H
#include "patchlevel.h"
#include "pyconfig.h"
#include "pyMacconfig.h"
#ifndef WITH_CYCLE_GC
#define WITH_CYCLE_GC 1
#endif
#include <limits.h>
#ifndef UCHAR_MAX
#error "Something's broken.  UCHAR_MAX should be defined in limits.h."
#endif
#if UCHAR_MAX != 255
#error "Python's source code assumes C's unsigned char is an 8-bit type."
#endif
#if defined(__sgi) && defined(WITH_THREAD) && !defined(_SGI_MP_SOURCE)
#define _SGI_MP_SOURCE
#endif
#include <stdio.h>
#ifndef NULL
#   error "Python.h requires that stdio.h define NULL."
#endif
#include <string.h>
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
#include <stdlib.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_STDDEF_H
#include <stddef.h>
#endif
#include <assert.h>
#include "pyport.h"
#ifndef DL_IMPORT	
#define DL_IMPORT(RTYPE) RTYPE
#endif
#ifndef DL_EXPORT	
#define DL_EXPORT(RTYPE) RTYPE
#endif
#if defined(Py_DEBUG) && defined(WITH_PYMALLOC) && !defined(PYMALLOC_DEBUG)
#define PYMALLOC_DEBUG
#endif
#if defined(PYMALLOC_DEBUG) && !defined(WITH_PYMALLOC)
#error "PYMALLOC_DEBUG requires WITH_PYMALLOC"
#endif
#include "pymath.h"
#include "pymem.h"
#include "object.h"
#include "objimpl.h"
#include "pydebug.h"
#include "unicodeobject.h"
#include "intobject.h"
#include "boolobject.h"
#include "lonGobject.h"
#include "floatobject.h"
#ifndef WITHOUT_COMPLEX
#include "complexobject.h"
#endif
#include "rangeobject.h"
#include "stringobject.h"
#include "memoryobject.h"
#include "bufferobject.h"
#include "bytesobject.h"
#include "bytearrayobject.h"
#include "tupleobject.h"
#include "listobject.h"
#include "dictobject.h"
#include "enumobject.h"
#include "setobject.h"
#include "methodobject.h"
#include "moduleobject.h"
#include "funcobject.h"
#include "classobject.h"
#include "fileobject.h"
#include "cobject.h"
#include "pycapsule.h"
#include "traceback.h"
#include "sliceobject.h"
#include "cellobject.h"
#include "iterobject.h"
#include "genobject.h"
#include "descrobject.h"
#include "warnings.h"
#include "weakrefobject.h"
#include "codecs.h"
#include "pyerrors.h"
#include "pystate.h"
#include "pyarena.h"
#include "modsupport.h"
#include "pythonrun.h"
#include "ceval.h"
#include "sysmodule.h"
#include "intrcheck.h"
#include "import.h"
#include "abstract.h"
#include "compile.h"
#include "eval.h"
#include "pyctype.h"
#include "pystrtod.h"
#include "pystrcmp.h"
#include "dtoa.h"
Pyapi_FUNC(PyObject*) _Py_Mangle(PyObject *p, PyObject *name);
#define PyArg_GetInt(v, a)	PyArg_Parse((v), "i", (a))
#define PyArg_NoArgs(v)		PyArg_Parse(v, "")
#define Py_CHARMASK(c)		((unsigned char)((c) & 0xff))
#include "pyfpe.h"
#define Py_single_input 256
#define Py_file_input 257
#define Py_eval_input 258
#ifdef HAVE_PTH
#include <pth.h>
#endif
#define PyDoc_VAR(name) static char name[]
#define PyDoc_STRVAR(name,str) PyDoc_VAR(name) = PyDoc_STR(str)
#ifdef WITH_DOC_STRINGS
#define PyDoc_STR(str) str
#else
#define PyDoc_STR(str) ""
#endif
#endif 

代码没几句,就是一堆头文件,而且在Python.h文件里没有找到 PyArg_ParseTuple()、Py_BuildValue()、PyMethodDef、PrMethods、METH_VARARGS、Py_InitModule这些变量或者函数。说实话,我第一看也纳闷呀,怎么Python.h文件里没有这些变量或者函数呢?所以很快就想到一定是在包含的头文件里的某些文件里,这么多,怎么找呀?我是写脚本程序找的,脚本程序很简单,在此就不贴代码了,几秒钟就找到了这些函数或者变量是在哪个文件里定义的。下面来一一介绍这几个变量或者函数吧,有不正确的地方,欢迎批评指正。

(1)PyArg_ParseTuple()

        该函数定义在/usr/include/python2.7/modsupport.h里。这个文件里有一段文字解释——”Module support interface“,也就是模块支持接口,这个文件里应该就是定义了对外扩展的接口。这个函数的原型是:

PyAPI_FUNC(int) PyArg_ParseTuple(PyObject *, const char *, ...)

该函数的功能是将Python对象C/c++类型数据,如果转换失败,返回0

第一个参数:包含从Python传递到C函数的参数列表的元组对象

第二个参数:是格式参数,必须是字符串,已经预定义好了的,零个或多个“格式单位”组成。一个格式单元描述一个Python对象。比如例子中的‘i'表示将Python整数对象转换为纯C语言的 int类型。

其余参数:其余参数必须是其类型由格式字符串确定的变量的地址,可以是多个地址。上面例子用的就      是num的地址&num表示的就是num的地址,&是取值运算符

一些常见的格式参数:

"s":将Python字符串或Unicode对象转换为C里面字符串的指针,即 Python中string o或者Unicode 对象转换为C语言里 char *

“s#”:“s”上的这个变体存储到两个C变量中,第一个是指向字符串的指针,第二个是它的长度。在这种情况下,Python字符串可能包含嵌入的空字节。如果可以进行这种转换,Unicode对象将传回指向对象的默认编码字符串版本的指针。所有其他读缓冲区兼容对象传回对原始内部数据表示的引用。即(字符串,Unicode或任何读取缓冲区兼容对象)→[char *,int]。

“z”:像“s”,但Python对象也可以是None,在这种情况下,C指针设置为NULL。即string或None)→[char *]

“z#”:(字符串或无或任何读缓冲区兼容对象)→[char *,int]。

“u”:将Python Unicode对象转换为C指针,指向16位Unicode(UTF-16)数据的空终止缓冲区。即(Unicode对象)→[Py_UNICODE *] 。

“u#”:这个变量“u”存储到两个C变量中,第一个是指向Unicode数据缓冲区的指针,第二个是它的长度。(Unicode对象)→[Py_UNICODE *,int]。

“es”:“s”上的此变体用于将Unicode和可转换为Unicode的对象编码为字符缓冲区。它只适用于没有嵌入NULL字节的编码数据。变量读取一个变量并存储到两个C变量中,第一个是指向编码名称字符串(编码)的指针,第二个是指向字符缓冲区的指针的指针,即(字符串,Unicode对象或字符缓冲区兼容对象)→[const char * encoding,char ** buffer]。

“es#”:类似”es",只是第三个指向整数的指针(* buffer_length,缓冲区长度)。编码名称必须映射到注册的编×××。如果设置为NULL,则使用默认编码。即(字符串,Unicode对象或字符缓冲区兼容对象)→[const char * encoding,char ** buffer,int * buffer_length]。

“h”:将Python整数转换为C short int,即(integer)→[short int]

“i”:将Python整数转换为纯C int。即(integer)→[int]

“l”:将Python整数转换为C long int,即(integer)→[long int]

“c”:将一个Python字符(表示为长度为1的字符串)转换为C char,即(长度为1的字符串)→[char]

“f”:将Python浮点数转换为C浮点,即(float)→[float]

“d”:将Python浮点数转换为C double,即(float)→[double]

“D”:将Python复杂数字转换为C Py_complex结构,即(复合物)→[Py_complex]

“O”:将Python对象(无任何转换)存储在C对象指针中。 C程序因此接收被传递的实际对象。对象的引用计数不增加。存储的指针不为NULL。(object)→[PyObject *]

“O!":将Python对象存储在C对象指针。这类似于“O”,但有两个C参数:第一个是Python类型对象的地址,第二个是存储对象指针的C变量(类型PyObject *)的地址。如果Python对象没有必需的类型,则会引发TypeError。(object)→[typeobject,PyObject *]

“O&”:通过转换器函数将Python对象转换为C变量。这需要两个参数:第一个是一个函数,第二个是C变量(任意类型)的地址,(object)→[converter,anything]

“S”:像“O”,但要求Python对象是一个字符串对象。如果对象不是字符串对象,则引发TypeError。 C变量也可以声明为PyObject *。(string)→[PyStringObject *]

“u”:像“O”,但要求Python对象是一个Unicode对象。如果对象不是Unicode对象,则引发TypeError。 C变量也可以声明为PyObject *。(Unicode字符串)→[PyUnicodeObject *]

“t#”:类似“s#”,但接受任何实现只读缓冲区接口的对象。 char *变量被设置为指向缓冲区的第一个字节,int被设置为缓冲区的长度。只接受单段缓冲对象;对所有其他类型引发TypeError。(只读字符缓冲区)→[char *,int]

“w”:类似于“s”,但接受实现读写缓冲器接口的任何对象。调用者必须通过其他方式确定缓冲区的长度,或者使用“w#”。只接受单段缓冲对象;对所有其他类型引发TypeError。(读写字符缓冲区)→[char *]

“w#”:类似“s#”,但接受任何实现读写缓冲区接口的对象。 char *变量被设置为指向缓冲区的第一个字节,int被设置为缓冲区的长度。只接受单段缓冲对象;对所有其他类型引发TypeError。(读写字符缓冲区)→[char *,int]

“items”:对象必须是Python序列,其长度是项目中的格式单位数。 C参数必须对应于各个格式单元initem。 可以嵌套序列的格式单元。(tuple)→[matching-items]


如果对Python源码稍微有点了解的话,PyObject 、PyStringObject 、PyUnicodeObject等都是Python源码里用C语言为Python定义的类型,有兴趣的可以看看《Python源码解析》这本书,里面都有介绍。


另外还有一些其他字符在格式字符串中有意义,

“|”:表示Python参数列表中的其余参数是可选的。 对应于可选参数的C变量应该被初始化为它们的默认值 - 当没有指定可选参数时,PyArg_ParseTuple()不触及相应的C变量的内容。

“:”:格式单元列表在这里结束; 冒号之后的字符串用作错误消息中的函数(“PyArg_ParseTuple()”引发的异常的“关联值”)。

“;”:格式单元列表在这里结束; 冒号之后的字符串用作错误消息,而不是默认错误消息。 显然,“:”和“;” 互相排斥。


(2)Py_BuildValue()

     该函数也是定义在/usr/include/python2.7/modsupport.h里,原型如下:

PyAPI_FUNC(PyObject *) Py_BuildValue(const char *, ...)


它的功能与PyArg_ParseTuple()正好相反,它是将C类型的数据结构转换成Python对象。

它第一个参数是格式参数,同PyArg_ParseTuple()格式参数一样,其余参数就是一些C类型的数据咯。

看几个例子吧,对它的理解会有帮助。

Py_BuildValue("") None

Py_BuildValue("i", 123) 123

Py_BuildValue("iii", 123, 456, 789) (123, 456, 789)

Py_BuildValue("s", "hello") 'hello'

Py_BuildValue("ss", "hello", "world") ('hello', 'world')

Py_BuildValue("s#", "hello", 4) 'hell'  #这个还有一个长度限制

Py_BuildValue("()") ()

Py_BuildValue("(i)", 123) (123,)

Py_BuildValue("(ii)", 123, 456) (123, 456)

Py_BuildValue("(i,i)", 123, 456) (123, 456)

Py_BuildValue("[i,i]", 123, 456) [123, 456]

Py_BuildValue("{s:i,s:i}", "abc", 123, "def", 456) {'abc': 123, 'def': 456}

Py_BuildValue("((ii)(ii)) (ii)", 1, 2, 3, 4, 5, 6) (((1, 2), (3, 4)), (5, 6))


(3)Py_InitModule()

该函数也是定义在/usr/include/python2.7/modsupport.h里,返回一个指针指向刚创建的模块对象,看名字也知道是初始化新建模块的。函数原型:

#define Py_InitModule(name, methods) \
	Py_InitModule4(name, methods, (char *)NULL, (PyObject *)NULL, \
		       PYTHON_API_VERSION)

是宏定义,接受两个参数,第一个参数为字符串,表示模块的名称;第二个参数是一个PyMethodDef的结构体数组,表示该模块都具有哪些方法。

PyMethodDef结构体有四个字段。 

* 第一个是一个字符串,表示在Python中对应的方法的名称; 

* 第二个是对应的C代码的函数; 

* 第三个是一个标致位,表示该Python方法是否需要参数,METH_NOARGS表示不需要参数,METH_VARARGS表示需要参数,这个参数在/usr/include/python2.7/methodobject.h有定义; 

* 第四个是一个字符串,它是该方法的__doc__属性,这个不是必须的,可以为NULL。 

其源代码如下:

struct PyMethodDef {
    const char	*ml_name;	
    PyCFunction  ml_meth;	
    int		 ml_flags;	
    const char	*ml_doc;	
};
typedef struct PyMethodDef PyMethodDef;

是在/usr/include/python2.7/methodobject.h中定义的。

PyMethodDef结构体数组最后以 {NULL, NULL, 0, NULL}结尾。(感觉好像不是必须的,但是通常都这么做那我们也这么做吧)不正之处,欢迎批评指正!


--结束END--

本文标题: 再探C/C++扩展Python

本文链接: https://www.lsjlt.com/news/189041.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 再探C/C++扩展Python
        上篇博文是初用c/c++扩展Python,只是简单的举个例子,有兴趣的可以去上篇博文里看看那个例子的代码,代码如下:#include<Python.h> static PyObject *pr_isprime(PyObj...
    99+
    2023-01-31
    再探 Python
  • Python 扩展使用 C/C++ 给
    本文来自作者 gashero 在 GitChat 上分享「Python 的 C 扩展开发惯例」,「阅读原文」查看交流实录 「文末高能」 编辑 | 嘉仔 目录 1   简介    1.1   Python扩展模块的用途和优点 ...
    99+
    2023-01-31
    Python
  • 为 Python 写一个 C++ 扩展模块
    使用 C 扩展为 Python 提供特定功能。在前一篇文章中,我介绍了 ​​六个 Python 解释器​​。在大多数系统上,CPython 是默认的解释器,而且根据民意调查显示,它还是最流行的解释器。Cpython 的独有功能是使用扩展 A...
    99+
    2023-05-14
    Python 模块 C++
  • Python的C扩展-应用与陷阱
    Python的C扩展-应用与陷阱 1. 背景 2. Python扩展的用武之地-库测试 (1)动态库的测试 (2)静态库的测试 3 python模块级扩展 4 小结 反馈建议 ...
    99+
    2023-01-31
    陷阱 Python
  • C# 扩展方法详解
    目录先来做一下MCSD试题;总结先来做一下MCSD试题;     答案是C; 题目是问怎么定义扩展方法; 下面来看一下扩展方法; 扩展方法是C# ...
    99+
    2024-04-02
  • 怎么为Python写一个C++扩展模块
    今天小编给大家分享一下怎么为Python写一个C++扩展模块的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。源代码和往常一样,...
    99+
    2023-07-06
  • 99%的人都不知道!Python、C、C 扩展、Cython 差异对比!
    我们以简单的斐波那契数列为例,来测试一下它们执行效率的差异。Python 代码:def fib(n): a, b = 0.0, 1.0 for i in range(n): a, b = a + b, a return aC 代码:doub...
    99+
    2023-05-14
    Python
  • 用 Go 编写的 Python 扩展会忽略 Ctrl+C
    php小编苹果发现,使用Go编写的Python扩展在处理Ctrl+C信号时可能会出现问题。通常情况下,当我们在命令行中按下Ctrl+C时,会发送一个SIGINT信号给正在运行的程序,以...
    99+
    2024-02-13
    overflow python安装
  • 如何实现C#扩展方法
    这篇文章将为大家详细讲解有关如何实现C#扩展方法,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。在我们的编程生涯中我们要使用很多很多类库,这些类库有的是我们自己开发的,我们有她的代码,有的是第三方发布的,我...
    99+
    2023-06-17
  • Python C扩展的引用计数问题分析
    这篇文章主要讲解了“Python C扩展的引用计数问题分析”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Python C扩展的引用计数问题分析”吧!Python GC机制对于Python这种...
    99+
    2023-06-19
  • C++11包扩展举例分析
    这篇文章主要讲解了“C++11包扩展举例分析”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“C++11包扩展举例分析”吧!简单扩展假设我们有下面的模板函数。这是一个简单的加法函数,将参数a,b...
    99+
    2023-06-19
  • python扩展
    补充一些有趣的知识   1. sys模块方法的补充,打印进度条 import sys,time for i in range(20): sys.stdout.write("#") sys.stdout.flush() ...
    99+
    2023-01-31
    python
  • C# 3.0中扩展方法怎么用
    这篇文章主要介绍了C# 3.0中扩展方法怎么用,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。Extension Methods 使用扩展方法,使用的时候需要注意的地方C# 3...
    99+
    2023-06-17
  • C#扩展性对象模型介绍
    这篇文章主要讲解了“C#扩展性对象模型介绍”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“C#扩展性对象模型介绍”吧!C#扩展性对象模型Visual Studio .NET 包含一个可编程、非...
    99+
    2023-06-17
  • C#中string常用扩展有哪些
    这篇文章主要为大家展示了“C#中string常用扩展有哪些”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“C#中string常用扩展有哪些”这篇文章吧。string是c#里面最最常用的类,和它的使...
    99+
    2023-06-17
  • 简化Python 编写C 扩展的语言Cython怎么用
    简化Python 编写C 扩展的语言Cython怎么用,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。Python 是当今使用最多的流行编程语言之一,因为:它是开源的,它有广...
    99+
    2023-06-02
  • 如何使用Cython为Python编写更快的C扩展
    本篇文章为大家展示了如何使用Cython为Python编写更快的C扩展,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。在我们这个包含了 7 个 PyPI 库的系列文章中学习解决常见的 Python 问...
    99+
    2023-06-16
  • C#下byte数组常用扩展浅析
    本篇内容介绍了“C#下byte数组常用扩展浅析”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!C# byte数组常用扩展应用一:转换为十六进制...
    99+
    2023-06-17
  • python之扩展
    17.2 非常简单的途径:Jython 和 IronPython 一个简单的java类public class JythonTest{ public void greeting(){ System.out.println("Hello,wo...
    99+
    2023-01-31
    python
  • C#常规扩展性模型是什么
    本篇内容介绍了“C#常规扩展性模型是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!C#常规扩展性模型VSProjectItem 对象是 ...
    99+
    2023-06-17
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作