python-ctypes模块中文帮助文档
- 格式:docx
- 大小:28.32 KB
- 文档页数:23
python中ctypes的使⽤尝试最近在看Python的性能优化⽅⾯的⽂章,突然想起ctypes这个模块,对于这个模块⼀直不是很理解,不过再次看完相关资料有了些新的观点。
ctypes 这个模块个⼈观点就是提供⼀个Python类型与C类型数据转换接⼝或者说是规则的⼀个模块。
ctypes定义的数据类型其实并不是⼀种数据类型,⽽更应该说是⼀种转换规则。
ctypes定义的数据类型都是需要和Python数据类型进⾏关联的,然后传给C函数进⾏调⽤,在C函数调⽤的时候是根据ctypes的数据类型进⾏转换的,把关联的Python数据类型转换为C数据类型传给C函数。
如果是ctypes定义的指针或者地址,其实是将Python变量对应的内存空间地址中的数据与ctypes数据类型进⾏关联,如果C函数内部对传过来的指针地址对应的变量进⾏修改,最后是ctypes将修改好的C数据类型转为Python类型数据并将其存⼊之前Python变量对应的内存空间中。
在调⽤ctypes时,程序的内存空间其实可以分为Python数据内存空间与C数据类型空间。
ctypes定义的数据类型就是提供了⼀个Python数据类型与C数据类型转换的对应关系。
ctypes定义的数据类型都是需要和Python数据类型关联的,在调⽤C函数的时候在实时的转为C数据类型。
其中,Python数据类型存在与Python数据内存空间中,C数据类型存在与C数据内存空间中。
需要注意的⼀点是,⼀般情况下C数据内存空间是实时开辟的,⽤完就及时⾃动销毁的,当然也有特例,那就是numpy定义的array类型变量等, numpy定义的数据类型其实就是⼀种经过包装的C数据类型,当然numpy定义的array等类型变量存在于C数据内存空间中,⽽numpy下的array是可以持续存在的,不会⾃动销毁。
ctypes 提供了⼀些基本数据类型⽤来映射 C 语⾔和 Python 的类型,可以这样说 ctypes 是提供的⼀种数据类型映射关系或是转换关系。
Python调用windows下DLL详解- ctypes库的使用分类:Python 2008-10-14 19:19 17710人阅读评论(12) 收藏举报pythondllwindowsstructurecclass作者:童磊(magictong)P.S. 之前的排版乱掉了,这里做一下排版,顺便改一下里面的一些用词错误。
2011-08-04在python中某些时候需要C做效率上的补充,在实际应用中,需要做部分数据的交互。
使用python中的ctypes模块可以很方便的调用windows的dll(也包括linux下的so等文件),下面将详细的讲解这个模块(以windows平台为例子),当然我假设你们已经对windows下怎么写一个DLL是没有问题的。
引入ctypes库[python] view plaincopyprint?from ctypes import *from ctypes import *假设你已经有了一个的DLL(名字是add.dll),且该DLL有一个符合cdecl(这里强调调用约定是因为,stdcall调用约定和cdecl调用约定声明的导出函数,在使用python加载时使用的加载函数是不同的,后面会有说明)调用约定的导出函数Add。
建立一个Python文件DllCall.py测试:[python] view plaincopyprint?from ctypes import *dll = CDLL("add.dll")print dll.Add(1, 102)from ctypes import *dll = CDLL("add.dll")print dll.Add(1, 102)结果:103上面是一个简单的例子。
下面简单聊一下调用流程:1、加载DLL上面已经说过,加载的时候要根据你将要调用的函数是符合什么调用约定的。
stdcall调用约定:两种加载方式[python] view plaincopyprint?Objdll = ctypes.windll.LoadLibrary("dllpath")Objdll = ctypes.WinDLL("dllpath")Objdll = ctypes.windll.LoadLibrary("dllpath")Objdll = ctypes.WinDLL("dllpath")cdecl调用约定:也有两种加载方式[python] view plaincopyprint?Objdll = ctypes.cdll.LoadLibrary("dllpath")Objdll = ctypes.CDLL("dllpath")<SPAN style="FONT-FAMILY: Microsoft YaHei">其实windll和cdll分别是WinDLL类和CDll类的对象。
python ctypes 回调函数在Python 中,使用ctypes模块可以调用动态链接库(DLL)中的函数,并支持回调函数的使用。
以下是一个简单的示例,演示如何在Python 中使用ctypes调用DLL 中的函数,并注册回调函数。
假设有一个名为example.dll的动态链接库,其中包含一个接受整数参数的函数register_callback,它会注册一个回调函数,并在后续调用时触发该回调函数。
// example.c#include <stdio.h>typedef void (*CallbackFunction)(int);static CallbackFunction callback = NULL;void register_callback(CallbackFunction cb) {callback = cb;}void trigger_callback(int value) {if (callback != NULL) {callback(value);}}编译这个C 文件生成动态链接库:gcc -shared -o example.dll -fPIC example.c然后,你可以使用以下Python 代码调用并测试这个动态链接库:import ctypes# 加载动态链接库example_dll = ctypes.CDLL('./example.dll')# 定义回调函数的类型CallbackFunction = ctypes.CFUNCTYPE(None, ctypes.c_int)# 实现回调函数def my_callback(value):print(f'Callback triggered with value: {value}')# 将回调函数传递给动态链接库中的函数example_dll.register_callback.argtypes = [CallbackFunction] example_dll.register_callback.restype = Noneexample_dll.register_callback(CallbackFunction(my_callback))# 调用触发回调的函数example_dll.trigger_callback(42)在这个例子中,CallbackFunction是一个特殊的函数类型,用于定义回调函数的签名。
Python:使用ctypes库调用外部DLL一、Python之ctypesctypes是Python的一个外部库,提供和C语言兼容的数据类型,可以很方便地调用C DLL中的函数。
在Python2.5官方安装包都带有ctypes 1.1版。
ctypes的官方文档在这里。
ctypes的使用非常简明,如调用cdecl方式的DLL只需这样:view sourceprint?1 from ctypes import *;2 h=CDLL('msvcrt.dll')3 h.printf('a=%d,b=%d,a+b=%d',1,2,1+2);以上代码运行后输出 a=1,b=2,a+b=3。
二、加载库和普通函数的调用官方API提供的库中有几个主要的函数:view sourceprint?01 //初始化02 int DCSPCLIENTDLL InitInterface( const char *pCenterIP, const unsigned short nUpLinkSvrPort,const unsigned short nDownLinkSvrPort );0304 //释放资源05 int DCSPCLIENTDLL FiniInterface( void );0607 //登录08 int DCSPCLIENTDLL Login( const unsigned int uiBranchPlatformID, const unsigned int nUserID, const char *pPassword );09 //注销10 int DCSPCLIENTDLL Logout( const unsigned int uiBranchPlatformID, const unsigned int nUserID, const char *pPassword );1112 //发车辆实时定位数据13 int DCSPCLIENTDLL SendUPRealLocation( const char * const pDeviceId, const char cDeviceColor,14 const unsigned short nMsgCode, const _stBPDynamicData * const pStGpsData );在Python中加载使用:view sourceprint?01 from ctypes import *0203 #加载API库04 api = CDLL('DCSPClientDLL.dll');05 #初始化函数的参数类型06 api.InitInterface.argtypes=[c_char_p,c_ushort,c_ushort]07 api.Login.argtypes=[c_uint,c_uint,c_char_p]08 api.Logout.argtypes=[c_uint,c_uint,c_char_p]0910 #初始化并登录11 api.InitInterface(u"中心服务器地址" , u'上行服务端端口' , u'下行客户端端口')12 api.Login(platformID,userID,password);13 #.....其它操作14 api.Logout(platformID,userID,password); #注销参数类型可以像上面的代码一样预先设定好,或者在调用函数时再把参数转成相应的c_***类型。
Python使用ctypes模块调用DLL函数之传递结构体参数引言在Python语言中,可以使用ctypes模块调用其它如C++语言编写的动态链接库DLL文件中的函数,在提高软件运行效率的同时,也可以充分利用目前市面上各种第三方的DLL库函数,以扩充Python软件的功能及应用领域,减少重复编写代码、重复造轮子的工作量,这也充分体现了Python语言作为一种胶水语言所特有的优势。
上篇已经讲了传递数值、指针、字符串参数的例子,详细细节请参考:这次讲一下在Python中使用ctypes模块调用DLL中的库函数传递结构体参数的情况。
同样,操作系统环境是win7 64位,Python使用的版本是python2.7.14,函数约定的调用方式为C调用(cdecl)方式。
例1:简单的结构体传递参数示例这个例子的功能是打印一个学生的信息,并返回一个指向字符串的指针。
其中,学生信息定义为一个结构体类型,包括学生的姓名、年龄及分数信息,该函数的声明及结构体定义如下图所示:函数printStudentInfo的具体C语言实现代码如下:在Python中的调用方式如下:从上面的代码中可以看出,对于结构体参数的传递,在Python中需要使用Structure作为基类定义一个与之对应的结构体类Student,在类的_fields中定义结构体中每个成员变量的名称和数据类型。
然后定义结构体类的一个实例对象student,对每个成员变量逐个赋值,以byref传址的方式进行调用就可以了。
例2:复杂结构体传递参数示例如果一个结构体里面包括了另一个结构体、指针等综合要素,情况就要复杂些了。
对上面的例子改进一下,定义一个People类,里面包含了一个指向Student类型的指针变量和一个整形变量,在这个结构体中存储多个学生的信息及学生的总数信息。
设计一个函数getPeopleInfo获取每个学生的信息,并返回所有学生的个数,该函数的声明及结构体定义如下图所示:函数getPeopleInfo的具体C语言实现代码如下:在Python中的调用方式如下:在上面的代码中,第43行定义了一个指向Student结构体的指针变量。
Python 手册Python中文社区Python 手册向上:Python 文档索引向后:前言Python 手册Guido van RossumFred L. Drake, Jr., editorPythonLabsEmail: **********************Release 2.3July 29, 2003前言目录1. 开胃菜2. 使用Python解释器2.1 调用解释器2.1.1 传递参数2.1.2 交互模式2.2 解释器及其工作模式2.2.1 错误处理2.2.2 执行 Python 脚本2.2.3 源程序编码2.2.4 交互环境的启动文件3.初步认识Python3.1 像使用计算器一样使用Python3.1.1 数值3.1.2 字符串3.1.3 Unicode 字符串3.1.4 链表3.2 开始编程4. 流程控制4.1 if 语法4.2 for 语法4.3 range() 函数4.4 break 和continue 语法以及else 子句在循环中的用法4.5 pass 语法4.6 定义函数4.7 定义函数的进一步知识4.7.1 定义参数变量4.7.2 参数关键字4.7.3 可变参数表4.7.4 Lambda 结构4.7.5 文档字符串5. 数据结构5.1 深入链表5.1.1 将链表作为堆栈来使用5.1.2 将链表作为队列来使用5.1.3 函数化的编程工具5.1.4 链表的内含(Comprehensions)5.2 del 语法5.3 Tuples 和 Sequences5.4 字典(Dictionaries)5.5 循环技巧5.6 深入条件控制5.7 Sequences 和其它类型的比较6. 模块6.1 深入模块6.1.1 模块搜索路径6.1.2 “编译” Python 文件6.2 标准模块6.3 dir() 函数6.4 包6.4.1 从包中导入所有内容(import * )6.4.2 隐式包引用6.4.3 包中的多重路径7. 输入和输出7.1 格式化输出7.2 读写文件7.2.1 文件对象的方法7.2.2 pickle 模块8. 错误和异常8.1 语法 Errors8.2 异常8.3 捕获异常8.4 释放异常8.5 用户自定义异常8.6 定义 Clean-up Actions9. 类9.1 一个术语9.2 Python 的生存期和命名空间9.3 类(Classes)的初步印像9.3.1 类定义语法9.3.2 类对象9.3.3 实例对象9.3.4 方法对象9.4 自由标记(Random Remarks)9.5 继承9.5.1 多继承9.6 私有变量9.7 零杂技巧9.8 异常也是类9.9 迭代子(Iterators)9.10 发生器(Generators)10. 接下来?A. 交互式编辑和历史回溯A.1 行编辑A.2 历史回溯A.3 快捷键绑定A.4 注释B. 浮点计算:问题与极限B.1 表达错误C. 历史和授权C.1 本软件的历史C.2 修改和使用Python的条件(Terms and conditions for accessing or otherwise usingPython)关于本文档Python 手册向上:Python 文档索引向后:前言Release 2.3, documentation updated on July 29, 2003.See A bout this document... for information on suggesting changes.Python中文社区前言Python中文社区Python 指南向前:Python 指南向上: P ython 指南向下:目录前言Copyright © 2001, 2002, 2003 Python Software Foundation. All rights reserved.Copyright © 2000 . All rights reserved.Copyright © 1995-2000 Corporation for National Research Initiatives. All rights reserved.Copyright © 1991-1995 Stichting Mathematisch Centrum. All rights reserved.See the end of this document for complete license and permissions information.概要:Python 是一种容易学习的强大语言。
【转】python中使⽤C类型的数组以及ctypes的⽤法【转⾃】Python 在 ctypes 中为我们提供了类似C语⾔的数据类型,它的⽤途(我理解的)可能是:(1)与其他语⾔(如 C、Delphi 等)写的动态连接库DLL 进⾏交换数据,因为 python 的数据与 DLL难以进⾏数据交换。
(2) python 的字符串⼀旦形成,是不可变的,为了算法的需要,我们有时需要对字符串进⾏原位操作 ( in place ),⽽不想浪费另外的内存空间。
(3) python 具有很简明的语法,⼈们乐于使⽤。
在解决实际问题时,字符串的处理占据了很⼤的开发量。
互联⽹上有很多有⽤的算法可以帮助我们解决问题,如果我们能⽤python 写类似于 C 语⾔的程序,就不需要⽤其他语去写扩展了。
有⼈会问,既然如此,⽤C语⾔,不就好了吗?当然可作这种选择,在⽤ python 的优势在于:既⽤使⽤了C语⾔的优点,也使⽤了Python的最⼤优点:垃圾⾃动回收,代码简洁等。
⼀、导⼊ C 类型库from ctypes import *⼆、常⽤的C 类型(1) c_int 、 c_long 、c_int32C 类型的long int ,这两个类型完全相同。
python ⽤ int 与之相应,但c_int的取值范围是 32 bit 的整数。
占⽤ 4 字节内存(2) c_int6464 bit 整数,占⽤ 8 字节内存, python ⽤ int 与之相应(2) c_double 、c_floatC 类型的 double , 这两个名字( c_double 、c_float 完全相同)占⽤ 8 字节内存python ⽤ float 与之相应(3) c_byteC 类型的 byte , python ⽤ int 与之相应占⽤1字节内存(4) c_charC 的 8 bit 字符型(5) c_wcharC 的 unicode 字符【注】ctypes模块C类型 Python类型 ctypes 类型char 1-character/string c_charwchar_t 1-character/Unicode、string c_wcharchar int/long c_bytechar int/long c_ubyteshort int/long c_shortunsigned short int/long c_ushortint int/long C_intunsigned int int/long c_uintlong int/long c_longunsigned long int/long c_ulonglong long int/long c_longlongunsigned long long int/long c_ulonglongfloat float c_floatdouble float c_doublechar *(NULL terminated) string or none c_char_pwchar_t *(NULL terminated) unicode or none c_wchar_pvoid * int/long or none c_void_p当⼀个函数期望⼀个指针作为参数时,可以像这样调⽤function_main( byref(parameter) ). //struct例⼦下⾯的例⼦是定义⼀个结构C语⾔例⼦struct beer_recipe{int amt_barley;int amt_barley;int amt_water;};Python例⼦class beer_recipe(Structure):_fields_ = [("amt_barley", c_int),("amt_water", c_int),]Union结构例⼦C语⾔例⼦union {long barley_long;int barley_int;char barley_char[8];}barley_amount;Python例⼦class barley_amount(Union):_fields_ = [("barley_long", c_long),("barley_int", c_int),("barley_char", c_char * 8),]三、⽣成类似C的数组⽬的:初值化⼀个具有 10 个元素的数组,每个元素初值为0的(⼀) python 原⽣数组 list>>> a = [ 0 ] * 10>>> for i in range(0, len(a)): print( a[i], end=" ")0 0 0 0 0 0 0 0 0 0 >>>(⼆)⽣成 10 元素的 c_int 类型的数组:格式⼀:>>> from ctypes import *>>> a = ( c_int * 10) ()>>> for i in range(0, len(a)):print( a[i], end=" ")0 0 0 0 0 0 0 0 0 0>>>格式⼆:>>> from ctypes import *>>> M = 10>>> a = ( c_int * M ) ()>>> for i in range(0, len(a)):print( a[i], end=" ")0 0 0 0 0 0 0 0 0 0格式三:>>> from ctypes import *>>> myArr10 = c_int * 10>>> a = myArr10( )>>> for i in range(0, len(a)):print( a[i], end=" ")0 0 0 0 0 0 0 0 0 0c_double 的数组定义与上⾯相似。
python与C语⾔调⽤模块ctypes的详解ctypes是python的⼀个函数库,提供和C语⾔兼容的数据类型,可以直接调⽤动态链接库中的导出函数。
为了使⽤ctypes,必须依次完成以下步骤:加载动态链接库将python对象转换成ctypes所能识别的参数使⽤ctypes所能识别的参数调⽤动态链接库中的函数动态链接库加载⽅式有三种:cdllwindlloledll它们的不同之处在于:动态链接库中的函数所遵守的函数调⽤⽅式(calling convention)以及返回⽅式有所不同。
cdll⽤于加载遵循cdecl调⽤约定的动态链接库,windll⽤于加载遵循stdcall调⽤约定的动态链接库,oledll与windll完全相同,只是会默认其载⼊的函数统⼀返回⼀个WindowsHRESULT错误编码。
函数调⽤约定:函数调⽤约定指的是函数参数⼊栈的顺序、哪些参数⼊栈、哪些通过寄存器传值、函数返回时栈帧的回收⽅式(是由调⽤者负责清理,还是被调⽤者清理)、函数名称的修饰⽅法等等。
常见的调⽤约定有cdecl和stdcall两种。
在《程序cdecl规定函数参数列表以从右到左的⽅式⼊栈,且由函数的调⽤者负责清除栈帧上的参数。
stdcall的参数⼊栈⽅式与cdecl⼀致,但函数返回时是由被调⽤者⾃⼰负责清理栈帧。
⽽且stdcall是Win32 API函数所使⽤的调⽤约定。
例⼦:Linux下:或者:其他例⼦:⼀个完整的例⼦:1,编写动态链接库// filename: foo.c#include "stdio.h"char* myprint(char *str){puts(str);return str;}float add(float a, float b){return a + b;}将foo.c编译为动态链接库:gcc -fPIC -shared foo.c -o foo.so2.使⽤ctypes调⽤foo.so#coding:utf8#FILENAME:foo.pyfrom ctypes import *foo = CDLL('./foo.so')myprint = foo.myprintmyprint.argtypes = [POINTER(c_char)] # 参数类型为char指针myprint.restype = c_char_p # 返回类型为char指针res = myprint('hello ctypes')print(res)add = foo.addadd.argtypes = [c_float, c_float] # 参数类型为两个floatadd.restype = c_float # 返回类型为floatprint(add(1.3, 1.2))执⾏:[jingjiang@iZ255w0dc5eZ test]$ python2.6 foo.pyhello ctypeshello ctypes2.5ctypes数据类型和C数据类型对照表查找动态链接库>>> from ctypes.util import find_library>>> find_library("m")'libm.so.6'>>> find_library("c")'libc.so.6'>>> find_library("bz2")'libbz2.so.1.0'函数返回类型函数默认返回 C int 类型,如果需要返回其他类型,需要设置函数的 restype 属性。
`ctypes` 是 Python 的一个库,它提供了一种方便的方法来调用动态链接库(DLL)或共享对象(.so)中的函数。
这在你需要使用 C 或 C++ 写的库时非常有用。
以下是一些 `ctypes` 的基本用法:1. 首先,你需要导入 `ctypes` 模块:```pythonimport ctypes```2. 然后,你需要定义你将要调用的动态链接库或共享对象的名称和路径。
例如,如果你的库名为 `mylib.dll`(在 Windows 上)或`libmylib.so`(在 Linux 上),你可以这样定义:```pythonmylib = ctypes.CDLL('mylib.dll') # 在 Windows 中mylib = ctypes.CDLL('libmylib.so') # 在 Linux 中```3. 现在,你可以使用 `mylib` 对象来调用你的 C 或 C++ 函数。
首先,你需要知道函数的名称,然后你需要知道函数的参数类型和返回类型。
这些信息都可以从你的 C 或 C++ 代码的文档中获取。
例如,假设你有一个名为 `add_numbers` 的函数,它接受两个`int` 参数并返回一个 `int` 值。
你可以这样调用它:```pythonresult = mylib.add_numbers(2, 3) # result 将会是 5```4. 如果你的函数是一个复杂的多参数函数,或者返回一个复杂的数据类型,你可能需要使用 `ctypes` 的更高级的特性。
例如,假设你的函数接受一个指向结构体的指针作为第一个参数,你可以这样做:```pythonclass MyStruct(ctypes.Structure):_fields_ = [("field1", ctypes.c_int), ("field2", ctypes.c_float)]my_struct = MyStruct()my_struct.field1 = 2my_struct.field2 = 3.14plex_function(my_struct, 42) # 调用一个接受MyStruct 指针和 int 值的函数```5. 对于返回复杂数据类型的函数,你可以使用`ctypes` 的`c_void_p` 类型来接收返回的数据,然后根据需要解析它。
pythonctypes中文帮助文档15.17。
ctypes- 用于Python的外部函数库2.5版中的新功能。
ctypes是Python的外部函数库。
它提供C兼容的数据类型,并允许在DLL或共享库中调用函数。
它可以用于在纯Python中包装这些库。
15.17.1。
ctypes教程注意:本教程中的代码示例doctest用于确保它们实际工作。
由于某些代码示例在Linux,Windows或Mac OS X下的行为不同,因此它们在注释中包含doctest指令。
注意:某些代码示例引用了ctypes c_int类型。
此类型是c_long32位系统上类型的别名。
因此,c_long如果您打算如果打印,则不应该感到困惑c_int- 它们实际上是相同的类型。
15.17.1.1。
加载动态链接库ctypes导出cdll,以及Windows windll和oledll对象,用于加载动态链接库。
您可以通过访问它们作为这些对象的属性来加载库。
cdll加载使用标准cdecl调用约定导出函数的库,而windll库使用stdcall 调用约定调用函数。
oledll还使用stdcall调用约定,并假定函数返回Windows HRESULT错误代码。
错误代码用于WindowsError在函数调用失败时自动引发异常。
以下是Windows的一些示例。
注意,它msvcrt是包含大多数标准C函数的MS标准C库,并使用cdecl调用约定:1.>>> from ctypes import *2.>>> print windll.kernel323.<WinDLL 'kernel32', handle ... at ...>4.>>> print cdll.msvcrt5.<CDLL 'msvcrt', handle ... at ...>6.>>> libc = cdll.msvcrt7.>>>Windows会.dll自动附加常用的文件后缀。
Python使用ctypes模块调用DLL函数之传递数值、指针与字符串参数引言在Python语言中,可以使用ctypes模块调用其它如C++语言编写的动态链接库DLL文件中的函数,在提高软件运行效率的同时,也可以充分利用目前市面上各种第三方的DLL库函数,以扩充Python 软件的功能及应用领域,减少重复编写代码、重复造轮子的工作量,这也充分体现了Python语言作为一种胶水语言所特有的优势。
这次以具体的例子讲一下在Python中,如何使用ctypes模块调用DLL中的库函数。
本文的编程系统环境是win7 64位,Python使用的版本是python2.7.14。
由于DLL中函数中传递的参数类型比较多样化,拟打算分三次讲解这部分内容,这次先讲传递数值、指针与字符串参数的情况,后面再分两次讲解传递结构体、数值数组等类型的情况。
DLL文件的加载假定已经有了一个DLL文件“MyDll.dll”,其函数约定的调用方式为C调用(cdecl)方式,则Python中加载该dll文件的代码如下:其中,第1行是引入ctypes模块,第2行是采用C调用约定加载“MyDll.dll”文件,并将返回值赋给dll变量,后续调用该DLL文件中的函数时,会使用该变量定义要使用的具体函数。
另外,需要说明的是,若DLL函数的调用约定是标准调用约定(stdcall)方式,则DLL文件的加载代码改为如下:dll = WinDLL(''MyDll.dll'')DLL函数的调用——函数参数为数值情况如对于“MyDll.dll”文件中的函数add,其函数声明如下:该函数有两个int类型的输入参数数x和y,返回的两个数的和。
其C语言的实现代码如下:在Python中的调用方式如下:这个函数应该说是最简单的一个函数了,在第17行,直接使用第一步加载DLL后返回的名称dll,后面跟函数名字即可返回其值。
DLL函数的调用——函数参数为指针情况对于上面的函数改进为add2,其函数C语言的实现代码如下:此时函数有三个指向int类型的指针参数x、y、z,z为x和y的和。
Python调⽤DLL动态链接库——ctypes使⽤最近要使⽤python调⽤C++编译⽣成的DLL动态链接库,因此学习了⼀下ctypes库的基本使⽤。
ctypes是⼀个⽤于Python的外部函数库,它提供C兼容的数据类型,并允许在DLL或共享库中调⽤函数。
⼀、Python调⽤DLL⾥⾯的导出函数1.VS⽣成dll1.1 新建动态链接库项⽬1.2 在myTest.cpp中输⼊以下内容:// myTest.cpp : 定义 DLL 应⽤程序的导出函数。
//#include "stdafx.h"#define DLLEXPORT extern "C" __declspec(dllexport) //放在 #include "stdafx.h" 之后//两数相加DLLEXPORT int sum(int a, int b) {return a + b;}注意:导出函数前⾯要加 extern "C" __declspec(dllexport) ,这是因为ctypes只能调⽤C函数。
如果不⽤extern "C",构建后的动态链接库没有这些函数的符号表。
采⽤C++的⼯程,导出的接⼝需要extern "C",这样python中才能识别导出的函数。
1.3⽣成dll动态链接库因为我的python3是64位的,所以VS⽣成的dll要选择64位的,如下所⽰:点击标题栏的⽣成 -> ⽣成解决⽅案1.4 查看⽣成的dll动态链接库2.Python导⼊dll动态链接库⽤python将动态链接库导⼊,然后调⽤动态链接库的函数。
为此,新建main.py⽂件,输⼊如下内容:from ctypes import *#----------以下四种加载DLL⽅式皆可—————————# pDLL = WinDLL("./myTest.dll")# pDll = windll.LoadLibrary("./myTest.dll")# pDll = cdll.LoadLibrary("./myTest.dll")pDll = CDLL("./myTest.dll")#调⽤动态链接库函数res = pDll.sum(1,2)#打印返回结果print(res)运⾏结果如下所⽰:⼆、Python调⽤DLL⾥⾯的实例⽅法更新全局变量值1.VS⽣成dll1.1 添加 mainClass 类,内容如下:mainClass.h:#pragma onceextern int dta;class mainClass{public:mainClass();~mainClass();void produceData();};mainClass.cpp:#include "stdafx.h"#include "mainClass.h"int dta = 0;mainClass::mainClass(){}mainClass::~mainClass(){}void mainClass::produceData() {dta = 10;}1.2 更改 myTest.cpp 内容myTest.cpp:#include "stdafx.h"#define DLLEXPORT extern "C" __declspec(dllexport) //放在 #include "stdafx.h" 之后#include "mainClass.h"//返回实例⽅法⾥⾯更新数据后的值DLLEXPORT int getRandData() {mainClass dataClass = mainClass();dataClass.produceData();return dta;}1.3 ⽣成64位dll2.Python导⼊dll动态链接库明显可以看出,在C++⾥设置的全局变量的值已经从0变为10了,说明python可以通过调⽤dll⾥⾯的实例⽅法来更新全局变量值三、Python_ctypes 指定函数参数类型和返回类型前⾯两个例⼦C++动态链接库导出函数的返回类型都是int型,⽽Python 默认函数的参数类型和返回类型为 int 型,所以Python 理所当然的以为 dll导出函数返回了⼀个 int 类型的值。
Python使⽤ctypes调⽤C函数在python中通过ctypes可以直接调⽤c的函数,⾮常简单易⽤下⾯就⼀步⼀步解释⽤法吧,以Linux为例讲解。
1,⾸先确定你的python⽀持不⽀持ctypespython2.7以后ctypes已经是标配了,2.4以后的版本得⾃⼰装下ctypes2,加载动态库两种加载⽅式>>> from ctypes import *>>> libc = cdll . LoadLibrary ( "libc.so.6" )>>> libc.printf("%d",2)>>> from ctypes import *>>> libc = CDLL ( "libc.so.6" )>>> libc.printf("%d",2)3, 调⽤系统函数上⾯的例⼦已经调⽤了系统函数printf,这⾥再给⼏个其他例⼦>>> from ctypes import *>>> libc = CDLL ( "libc.so.6" )>>> print libc . time ( None )1308019893>>> print libc.atoi("234")2344,ctypes 数据类型和 C数据类型对照表ctypes type C type Python type_Bool bool (1)char1-character stringwchar_t1-character unicode stringchar int/longunsigned char int/longshort int/longunsigned short int/longint int/longunsigned int int/longlong int/longunsigned long int/long__int64 or long long int/longunsigned __int64 or unsigned long long int/longfloat floatdouble floatlong double floatctypes type C type Python typechar * (NUL terminated)string or Nonewchar_t * (NUL terminated)unicode or Nonevoid *int/long or None这些数据都可以⽤⼀个默认值进⾏创建>>> c_int()c_long(0)>>> c_char_p("Hello, World")c_char_p('Hello, World')>>> c_ushort(-3)c_ushort(65533)>>>这些数据也可以被改变:>>> i = c_int(42)>>> print ic_long(42)>>> print i.value42>>> i.value = -99>>> print i.value-99>>>赋值给 c_char_p,c_wchar_p,c_void_p只改变他们指向的内存地址,⽽不是改变内存的内容>>> s = "Hello, World">>> c_s = c_char_p(s)>>> print c_sc_char_p('Hello, World')>>> c_s.value = "Hi, there">>> print c_sc_char_p('Hi, there')>>> print s # first string is unchangedHello, World>>>如果需要可改变内容的字符串,需要使⽤ create_string_buffer()>>> from ctypes import *>>> p = create_string_buffer(3) # create a 3 byte buffer, initialized to NUL bytes>>> print sizeof(p), repr(p.raw)3 '/x00/x00/x00'>>> p = create_string_buffer("Hello") # create a buffer containing a NUL terminated string >>> print sizeof(p), repr(p.raw)6 'Hello/x00'>>> print repr(p.value)'Hello'>>> p = create_string_buffer("Hello", 10) # create a 10 byte buffer>>> print sizeof(p), repr(p.raw)10 'Hello/x00/x00/x00/x00/x00'>>> p.value = "Hi">>> print sizeof(p), repr(p.raw)10 'Hi/x00lo/x00/x00/x00/x00/x00'>>>5,函数返回类型函数默认返回 C int 类型,如果需要返回其他类型,需要设置函数的 restype 属性>>> strchr = libc.strchr>>> strchr("abcdef", ord("d")) # doctest: +SKIP8059983>>> strchr.restype = c_char_p # c_char_p is a pointer to a string>>> strchr("abcdef", ord("d"))'def'>>> print strchr("abcdef", ord("x"))None>>>6,传递指针或者引⽤很多情况下 C 函数需要传递指针或者引⽤,ctypes也完美的⽀持这⼀点byref() ⽤来传递引⽤参数,pointer() 函数也可以完成同样的⼯作,但pointer()会创建⼀个实际的指针对象,如果你不需要⼀个指针对象,⽤byref()会快很多>>> i = c_int()>>> f = c_float()>>> s = create_string_buffer('/000' * 32)>>> print i.value, f.value, repr(s.value)0 0.0 ''>>> libc.sscanf("1 3.14 Hello", "%d %f %s",... byref(i), byref(f), s)3>>> print i.value, f.value, repr(s.value)1 3.1400001049 'Hello'>>>7,结构体和联合结构体和联合必须从 Structure 和 Union 继承,⼦类必须定义_fields_ 属性,_fields_ 属性必须是⼀个2元组的列表,包括⼀个field名字和field的类型field类型必须是⼀个ctypes的类型例如 c_int, 或者其他继承⾃ctypes的类型,结构体,联合,数组,指针。
【python基础】ctypes使⽤的变量、指针、引⽤和buffer 程序如下,学习关注点见备注内容# -*- coding: utf-8 -*-from ctypes import *import sysprint '-'*100python_str = 'tests中国⼈' # 中⽂占4字节print 'python_string', python_strprint 'len:', len(python_str) # 字符长度,中⽂占3个长度,不含类似于C语⾔的结束符print 'getsizeof', sys.getsizeof(python_str)# print 'byref', byref(python_str) # byref参数必须是ctypes类型# print 'sizeof', sizeof(python_str) # sizeof参数必须是ctypes类型print '-'*100c_str_p = c_char_p(python_str)print 'c_str_p', c_str_p# print 'len:', len(c_str_p) # pointer没有lenprint 'getsizeof', sys.getsizeof(c_str_p) # 整个对象在python中占⽤的字节数print 'sizeof', sizeof(c_str_p) # 指针地址占⽤的字节数print 'addressof', hex(addressof(c_str_p)) # 纯地址print 'byref', byref(c_str_p) # 引⽤指针print 'string_at', string_at(c_str_p) # 获取内容print 'string_at 0-4', string_at(c_str_p, 4) # 获取内容print '-'*100c_str_buffer = c_buffer(python_str)print 'c_str_buffer', c_str_bufferprint 'getsizeof', sys.getsizeof(c_str_buffer)print 'sizeof', sizeof(c_str_buffer) # 字节数,⼀个中⽂字符占3个字节,⼀个英⽂字符占1个字节,结束符占⼀个字节print 'addressof', hex(addressof(c_str_buffer)) # 纯地址print 'byref', byref(c_str_buffer) # 引⽤指针print 'c_str_buffer.value', c_str_buffer.value # 获取内容print 'c_str_buffer[:4]', c_str_buffer[:4] # 截取内容print '-'*100c_num_long = c_long(0xfff)print 'c_num_long', c_num_long # 对象本⾝print 'value', c_num_long.value # 值print 'sizeof', sizeof(c_num_long)print '-'*100c_num_int = c_int(123)print 'c_num_int', c_num_int # 对象本⾝print 'value', c_num_int.value # 值print 'sizeof', sizeof(c_num_int)print '-'*100c_num_int64 = c_int64(123)print 'c_num_int64', c_num_int64 # 对象本⾝print 'value', c_num_int64.value # 值print 'sizeof', sizeof(c_num_int64)运⾏结果C:\Python27\python.exe C:/code/cetc/engine/DistributedNode/test.py----------------------------------------------------------------------------------------------------python_string tests中国⼈len: 14getsizeof 47----------------------------------------------------------------------------------------------------c_str_p c_char_p('tests\xe4\xb8\xad\xe5\x9b\xbd\xe4\xba\xba')getsizeof 128sizeof 8addressof 0x24f8a10Lbyref <cparam 'P' (00000000024F8A10)>string_at tests中国⼈string_at 0-4 test----------------------------------------------------------------------------------------------------c_str_buffer <ctypes.c_char_Array_15 object at 0x00000000024F8A48> getsizeof 128sizeof 15addressof 0x24f8a90Lbyref <cparam 'P' (00000000024F8A90)>c_str_buffer.value tests中国⼈c_str_buffer[:4] test----------------------------------------------------------------------------------------------------c_num_long c_long(4095)value 4095sizeof 4----------------------------------------------------------------------------------------------------c_num_int c_long(123)value 123sizeof 4----------------------------------------------------------------------------------------------------c_num_int64 c_longlong(123L)value 123sizeof 8Process finished with exit code 0。
ctypes模块Python 和 C 的混合编程⼯具有很多,这⾥介绍 Python 标准库⾃带的 ctypes 模块的使⽤⽅法。
ctypes是Python的⼀个外函数库。
它提供了C兼容的数据类型,并允许在dll或共享库中调⽤函数。
它可以⽤纯Python封装这些库。
初识Python 的 ctypes 要使⽤ C 函数,需要先将 C 编译成动态链接库的形式,即 Windows 下的 .dll ⽂件,或者 Linux 下的 .so ⽂件。
先来看⼀下 ctypes 怎么使⽤ C 标准库。
Windows 系统下的 C 标准库动态链接⽂件为 msvcrt.dll (⼀般在⽬录 C:\Windows\System32 和 C:\Windows\SysWOW64 下分别对应 32-bit 和 64-bit,使⽤时不⽤刻意区分,Python 会选择合适的)Linux 系统下的 C 标准库动态链接⽂件为 libc.so.6 (以 64-bit Ubuntu 系统为例,在⽬录 /lib/x86_64-linux-gnu 下)例如,以下代码⽚段导⼊ C 标准库,并使⽤ printf 函数打印⼀条消息,import platformfrom ctypes import *if platform.system() == 'Windows':libc = cdll.LoadLibrary('msvcrt.dll')elif platform.system() =='Linux':libc = cdll.LoadLibrary('libc.so.6')libc.printf('Hello ctypes!\n')另外导⼊dll⽂件,还有其它⽅式如下,详细解释请参阅 ctypes module 相关⽂档,import platformfrom ctypes import *if platform.system() == 'Windows':libc = cdll.LoadLibrary('msvcrt.dll')#libc = windll.LoadLibrary('msvcrt.dll') # Windows only#libc = oledll.LoadLibrary('msvcrt.dll') # Windows only#libc = pydll.LoadLibrary('msvcrt.dll')#libc = CDLL('msvcrt.dll')#libc = WinDLL('msvcrt.dll') # Windows only#libc = OleDLL('msvcrt.dll') # Windows only#libc = PyDLL('msvcrt.dll')elif platform.system() =='Linux':libc = cdll.LoadLibrary('libc.so.6')#libc = pydll.LoadLibrary('libc.so.6')#libc = CDLL('libc.so.6')#libc = PyDLL('libc.so.6')libc.printf('Hello ctypes!\n')ctype数据类型ctypes 作为 Python 和 C 联系的桥梁,它定义了专有的数据类型来衔接这两种编程语⾔。
python ctypes 代码
当使用Python的ctypes库时,我们通常是为了调用动态链接库(DLL)中的函数。
下面是一个简单的示例代码,演示了如何使用ctypes库加载动态链接库并调用其中的函数:
python.
import ctypes.
# 加载动态链接库。
my_dll = ctypes.CDLL('my_library.dll')。
# 定义函数参数和返回类型。
my_dll.my_function.restype = ctypes.c_int.
my_dll.my_function.argtypes = [ctypes.c_int,
ctypes.c_int]
# 调用函数。
result = my_dll.my_function(1, 2)。
print(result)。
在这个示例中,我们首先使用`ctypes.CDLL`加载了名为
`my_library.dll`的动态链接库。
然后,我们定义了`my_function`
函数的参数类型和返回类型。
最后,我们调用了该函数并打印了结果。
需要注意的是,`my_library.dll`是一个虚构的动态链接库名称,实际应用中需要替换成你要调用的动态链接库的名称。
另外,
`my_function`、参数类型和返回类型也需要根据实际情况进行替换。
总的来说,使用ctypes库可以让我们在Python中方便地调用
C或C++编写的动态链接库中的函数,从而实现Python与其他语言
的互操作。
希望这个简单的示例能帮助你更好地理解如何使用
ctypes库。
使用python的内置ctypes模块与c、c++写的dll进行交互from ctypes import *dll = CDLL("add.dll")#加载cdecl的dll。
另外加载stdcall的dll 的方式是WinDLL("dllpath")sum=dll.Add(1, 102)p=1sum=dll.sub(2, byref(p))#通过库中的byref关键字来实现C代码如下:typedef struct{char words[10];}keywords;typedef struct{keywords *kws;unsigned int len;}outStruct;extern "C"int __declspec(dllexport) test(outStruct *o);int test(outStruct *o){unsigned int i = 4;o->kws = (keywords *)malloc(sizeof(unsigned char) * 10 * i);strcpy(o->kws[0].words, "The First Data");strcpy(o->kws[1].words, "The Second Data");o->len = i;return 1;}Python代码如下:class keywords(Structure):_fields_ = [('words', c_char *10),]class outStruct(Structure):_fields_ = [('kws', POINTER(keywords)),('len', c_int),]o = outStruct()dll.test(byref(o))print (o.kws[0].words)print (o.kws[1].words)print (o.len)•调用Windows API#导入ctypes模块from ctypes import *er32.MessageBoxW(0, '内容!', '标题', 0)#也可以用以下方式为API函数建立个别名后再进行调用MessageBox = er32.MessageBoxWMessageBox(0, '内容!', '标题', 0)运行结果预览。
python模块说明文档
Python模块的说明文档是对该模块功能和使用方法的详细描述和介绍。
它包含了关于模块的各种信息,如模块的名称、版本、作者、依赖关系等。
模块说明文档一般以文本文件的形式存在,在Python标准库中常以.rst、.txt 或.md等格式来编写。
可以使用文本编辑器编写模块说明文档,也可以使用reStructuredText工具(Sphinx)来自动生成文档。
模块说明文档一般分为以下几个部分:
1. 模块名称和版本:模块的名称和当前的版本信息。
2. 模块功能:对模块的功能进行详细的介绍,包括模块的主要功能和特性。
3. 安装和使用:对模块的安装和使用方法进行详细的说明,包括安装依赖、导入模块、使用模块的函数或类等。
4. API文档:对模块中的每个函数、类或方法进行详细的说明,包括参数、返回值、用法示例等。
5. 示例代码:给出使用模块的一些示例代码,以便用户更好地理解模块的使用方法。
6. 作者和贡献者:列出模块的作者和其他贡献者的信息。
7. 附加信息:包括模块的许可证信息、依赖关系等其他附加信息。
编写模块说明文档是一个好的编程实践,它可以帮助使用者快速了解模块的功能和使用方法,提高代码的可读性和易用性。
内容:.加载动态链接库.从已加载的dll中引用函数.调用函数1.基本的数据类型.调用函数2.用自己的数据类型调用函数.确认需要的参数类型(函数原型).返回值.传递指针.结构和联合.结构或联合的对齐方式和字节的顺序.结构和联合中的位.数组.指针.类型转换.未完成的类型.回调函数.访问dlls导出的值.可变长度的数据类型.bugs 将要做的和没有做的事情注意:本文中的代码例子使用doctest确保他们能够实际工作。
一些代码例子在linux和windows以及苹果机上执行有一定的差别注意:一些代码引用了ctypes的c_int类型。
它是c_long在32位机子上的别名,你不应该变得迷惑,如果你期望的是c_int类型,实事上打印的是c_long,它们实事上是相同的类型。
加载动态链接库ctypes加载动态链接库,导出cdll和在windows上同样也导出windll和oledll对象。
加载动态链接库后,你可以像使用对象的属性一样使用它们。
cdll加载使用标准的cdecl调用约定的链接库,而windll库使用stdcall调用约定,oledll也使用stdcall调用约定,同时确保函数返回一个windows HRESULT错误代码。
这错误代码自动的升为WindowsError Python exceptions,当这些函数调用失败时。
这有一些windows例子,msvcrt是微软的c标准库,包含大部分的标准c函数,同时使用cdecl调用约定。
注:cdecl和stdcall的区别请见/log-20.html>>> from ctypes import *>>> print windll.kernel32 # doctest: +WINDOWS<WinDLL 'kernel32', handle ... at ...>>>> print cdll.msvcrt # doctest: +WINDOWS<CDLL 'msvcrt', handle ... at ...>>>> libc = cdll.msvcrt # doctest: +WINDOWS>>>windows自动添加常用的.dll文件后缀名在linux上,需要使用包含扩展名的文件名来加载一个库,因此属性操作不能正常使用。
或者使用dll加载器的LoadLibrary方法,或者通过CDLL构造函数创建一个CDLL的一个实例>>> cdll.LoadLibrary("libc.so.6") # doctest: +LINUX<CDLL 'libc.so.6', handle ... at ...>>>> libc = CDLL("libc.so.6") # doctest: +LINUX>>> libc # doctest: +LINUX<CDLL 'libc.so.6', handle ... at ...>>>>加载dll使用其中函数使用函数就像对象的属性>>> from ctypes import *>>> libc.printf<_FuncPtr object at 0x...>>>> print windll.kernel32.GetModuleHandleA # doctest: +WINDOWS<_FuncPtr object at 0x...>>>> print windll.kernel32.MyOwnFunction # doctest: +WINDOWSTraceback (most recent call last):File "<stdin>", line 1, in ?File "ctypes.py", line 239, in __getattr__func = _StdcallFuncPtr(name, self)AttributeError: function 'MyOwnFunction' not found>>>00注意win32系统dll像kernel32和user32大部分导出ANSI和UNICODE版本函数,UNICODE 版本以一个W结尾导出而ANSI版本则以一个A结尾导出的。
win32 GetModuleHandle函数,返回一个指定的module 名字的module句柄下面c原型,GetModuleHandle的macro,依赖于它是不是UNICODE。
/* ANSI version */HMODULE GetModuleHandleA(LPCSTR lpModuleName);/* UNICODE version */HMODULE GetModuleHandleW(LPCWSTR lpModuleName);windll不会神奇的自已去选择一个,你必须显式确认GetModuleHandleA或者GetModuleHandleW去使用它们去处理一般字符串或unicode字符串。
有时候,dll导出函数名,python无法识别,像"??2@YAPAXI@Z". 在这情况下,你必须使用getattr去使用这些函数>>> getattr(cdll.msvcrt, "??2@YAPAXI@Z") # doctest: +WINDOWS<_FuncPtr object at 0x...>>>>在windows上,一些dllS不是导出函数名,而是以顺序,这些函数可以将这些数字当作dll 对象的索引来使用这些函数。
>>> cdll.kernel32[1] # doctest: +WINDOWS<_FuncPtr object at 0x...>>>> cdll.kernel32[0] # doctest: +WINDOWSTraceback (most recent call last):File "<stdin>", line 1, in ?File "ctypes.py", line 310, in __getitem__func = _StdcallFuncPtr(name, self)AttributeError: function ordinal 0 not found>>>调用函数你可调用这些函数,像其它的python函数一样,下面的例子使用time()函数,它以秒为单位返回从unix新纪元的系统时间,GetModuleHandleA()函数,返回一个win32模块句柄。
下面的例子用空指针调用函数(None作为空指针)>>> print libc.time(None) # doctest: +SKIP1150640792>>> print hex(windll.kernel32.GetModuleHandleA(None)) # doctest: +WINDOWS0x1d000000>>>ctypes尝试阻止你以错误的参数数量或调用约定来调用函数。
不幸的是,这些仅仅能在windows上工作它在函数返回后不会去检查这栈,尽管在调用函数后有错误发生。
>>> windll.kernel32.GetModuleHandleA() # doctest: +WINDOWSTraceback (most recent call last):File "<stdin>", line 1, in ?ValueError: Procedure probably called with not enough arguments (4 bytes missing)>>> windll.kernel32.GetModuleHandleA(0, 0) # doctest: +WINDOWSTraceback (most recent call last):File "<stdin>", line 1, in ?ValueError: Procedure probably called with too many arguments (4 bytes in excess)>>>产生了同样的exception,当你用cdecl调用约定去使用一个stdcall函数,反之亦然。
>>> cdll.kernel32.GetModuleHandleA(None) # doctest: +WINDOWSTraceback (most recent call last):File "<stdin>", line 1, in ?ValueError: Procedure probably called with not enough arguments (4 bytes missing)>>>>>> windll.msvcrt.printf("spam") # doctest: +WINDOWSTraceback (most recent call last):File "<stdin>", line 1, in ?ValueError: Procedure probably called with too many arguments (4 bytes in excess)>>>找到正确的调用约定,你必须检查c头文件或者你想调用的函数的文档。
在windows,ctypes使用win32结构exception处理一般的保护错误阻止crashes,当调用无效的参数值>>> windll.kernel32.GetModuleHandleA(32) # doctest: +WINDOWSTraceback (most recent call last):File "<stdin>", line 1, in ?WindowsError: exception: access violation reading 0x00000020>>>然而有很多种可能性会发生crash,你使用python的ctypes,你应该足够的小心。