2010-01-24 17:58 14237人阅读 评论(11)

我实现

Python C API

此部分可以参考我原来的文章《

准备工作:

闲话少说,看看Python C API。事实上,Python C

API比起Lua的API了来说,清晰了很多,这也符合Pythonic的风格,就算这时Python

C API是设计给C语言使用者使用的,还是这样的风格,比起Lua API那种汇编式的接口,(据说为了效率,可以直接操作每个数据)强了太多了。

要使用Python C API,用普通的二进制包是不行的,得下源码包。这里我用3.1.1的源码包为例:Source Distribution

Python的源码在Windows的版本中已经完全换到VS2008了,直接用VS2008打开在PCbuild目录下的工程即可,对于VS2005及

以前的用户打开PC目录下的其他版本工程。我们编译debug版本的pythoncore会得到

python31_d.lib,python31_d.dll两个文件,需要的头文件在Include目录下,还需要将pyconfig.h文件从

PCBuild目录下拷贝到Include中,(硬要直接指定也可以)这样准备工作就已经齐了。

Python C API有两个方向的使用方式,从C中调用Python脚本及利用C扩展Python。

先讲简单的从C中调用Python,也就是常说的在C中内嵌Python。

C中内嵌Python

新建立一个工程,首先需要将工作目录设置到Python-3.1.1PCbuild中,以获取到动态库,至于静态库的包含,Include目录的指定,那自然也是少不了的。文件中需要包含Python.h文件,这也是必须的。

接口中

Py_Initialize();

Py_Finalize();

一对的调用是必须的,一个用于初始化Python的动态库,一个用于释放。释放时会输出[31818 refs],意义不明。

PyRun_SimpleString

可用于执行简单的Python语句。如下:

#include

"python.h"

int

main(int

argc, char

* argv[])

{

Py_Initialize();

PyRun_SimpleString("print(

"

Hello World

"

)"

);

Py_Finalize();

system("PAUSE"

);

return

0

;

}

此时,输出为:

Hello World

[31829 refs]

请按任意键继续. . .

此时可以执行一些Python语句了,并且,特别需要注意的是,在一个Py_Initialize();与Py_Finalize();之间,Python语句执行是在同一个执行环境中,不懂什么意思?看个示例就知道了。

int

main(int

argc, char

* argv[])

{

Py_Initialize();

PyRun_SimpleString("str =

"

Hello World

"

"

);

PyRun_SimpleString("print(str)"

);

Py_Finalize();

system("PAUSE"

);

return

0

;

}

此例与上例输出是一样的,懂我的意思了吧?意思就是以前执行的语句对后面的语句是有效的,相当于在同一个交互式命令行中顺序执行语句。

获取返回值

PyRun_SimpleString有的缺点,文档中的描述是:

Returns 0

on success or

-1

if an exception was

raised.

那么你就无法在Python及C语言中传递任何信息。我们需要高级点的函数才行。

PyObject* PyRun_String(const char *str, int start, PyObject *globals, PyObject *locals)

就是干这个的。

但是需要注意的是此函数的一些参数的获取,按照想当然的给他们置空可是不行的,如下例所示:

#include

"python.h"

int

main(int

argc, char

* argv[])

{

Py_Initialize();

PyRun_SimpleString("x = 10"

);

PyRun_SimpleString("y = 20"

);

PyObject* mainModule = PyImport_ImportModule("__main__"

);

PyObject* dict = PyModule_GetDict(mainModule);

PyObject* resultObject = PyRun_String("x + y"

, Py_eval_input, dict, dict);

if

(resultObject)

{

long

result = PyLong_AsLong(resultObject);

printf("

%d

"

, result);

Py_DECREF(resultObject);

}

Py_Finalize();

system("PAUSE"

);

return

0

;

}

这里我利用了一个知识,那就是

PyRun_SimpleString实际是将所有的代码都放在

__main__

模块中运行,注意啊,没有导入正确的模块及其dict,你会运行失败,失败的很惨。至此,C语言已经于Python来了个交互了。

呵呵,突然觉得深入下去就没有尽头了。。。。。。。还是点到为止吧。

稍微深入点的可以去看《Programming Python》一书。在啄木鸟

上有此书及一些译文。Part VI: Integration 部分Chapter 23. Embedding Python,有相关的知识。

利用C扩展Python

此部分在《Programming Python》的Chapter 22. Extending Python 部分有介绍。

这里也只能开个头了,最多告诉你,其实,这些都没有什么难的。稍微复杂点的情况《#include

"Python.h"

static

PyObject *

ex_foo(PyObject *self, PyObject *args)

{

printf("Hello, world

n

"

);

Py_INCREF(Py_None);

return

Py_None;

}

static

PyMethodDef example_methods[] = {

{"foo"

, ex_foo, METH_VARARGS, "foo() doc string"

},

{NULL

, NULL

}

};

static

struct

PyModuleDef examplemodule = {

PyModuleDef_HEAD_INIT,

"example"

,

"example module doc string"

,

-1

,

example_methods,

NULL

,

NULL

,

NULL

,

NULL

};

PyMODINIT_FUNC

PyInit_example(void

)

{

return

PyModule_Create(&examplemodule);

}

这个例子包含了全部C语言为Python写扩展时的基本信息:

1.PyInit_example是最后的出口,其中需要注意的是example不仅仅代表example的意思,还代表了最后生成的库会用example命名,也就是你调用此库会需要使用

import example

的形式。

2.static

struct

PyModuleDef examplemodule的存在也是必须的,指定了整个模块的信息,比如上面

的"example module doc string",模块的说明文字。每个参数的含义上面已经有些演示了。

全部内容可以参考文档中关于PyModuleDef的说明

3.example_methods是一个函数列表,事实上表示此模块中含有的函数。此例中仅含有

foo一个函数。

static

PyObject *

ex_foo(PyObject *self, PyObject *args)

{

printf("Hello, world

n

"

);

Py_INCREF(Py_None);

return

Py_None;

}

就是整个函数的具体实现了,此函数表示输出"Hello, world",还是hello world。。。。。。。。这个world还真忙啊。。。。天天有人say hello。

这个Python本身附带的例子有点太简单了,我给出一个稍微复杂点的例子,还是我最喜欢的MessageBox,最后的效果自然还是Hello world。。。。。。。。。。。

#include

static

PyObject *

MessageBox(PyObject *self, PyObject *args)

{

LPCSTR lpText;

LPCSTR lpCaption;

UINT uType;

PyArg_ParseTuple(args, "ssi"

, &lpText, &lpCaption, &uType);

int

result = MessageBoxA(0

, lpText, lpCaption, uType);

PyObject* resultObject = Py_BuildValue("

%i

"

, result);

return

resultObject;

}

static

PyMethodDef c_methods[] = {

{"MessageBox"

, MessageBox, METH_VARARGS, "MessageBox() "

},

{NULL

, NULL

}

};

static

struct

PyModuleDef win32module = {

PyModuleDef_HEAD_INIT,

"Win32API"

,

"Win32 API MessageBox"

,

-1

,

c_methods,

NULL

,

NULL

,

NULL

,

NULL

};

PyMODINIT_FUNC

PyInit_Win32API(void

)

{

return

PyModule_Create(&win32module);

}

需要注意的还是需要注意,唯一有点区别的是这里我有从Python中传进来的参数及从C中传出去的返回值了。

PyArg_ParseTuple

用于解析参数

Py_BuildValue 用于构建一个Python的值返回

他们的构建和解析形式有点类似于sprintf等C常见的形式,可是每个字符代表的东西不一定一样,需要注意,文档中比较详细,此例中展示的是String及int的转换。

以生成动态库的方式编译此文件后,并指定为Win32API.pyd文件,然后将其拷贝到Python_d所在的目录(用Python3.1.1源代码生成的调试版本Python),此时import会首先查找*_d.pyd形式的动态库,不然只会搜索release版。

首先看看库的信息:

>>> import Win32API

[44692 refs]

>>> dir(Win32API)

['MessageBox', '__doc__', '__file__', '__name__', '__package__']

[44705 refs]

>>> help(Win32API)

Help on module Win32API:

NAME

Win32API - Win32 API MessageBox

FILE

d:python-3.1.1pcbuildwin32api_d.pyd

FUNCTIONS

MessageBox(...)

MessageBox()

[68311 refs]

注意到文档的作用了吧?还注意到dir的强大。。。。。。。。。。。。。此时MessageBox已经在Win32API中了,直接调用吧。我这里忽略了窗口的句柄,需要注意。

多么繁忙的World啊。。。。。。。。

此时你会想,太强大了,我要将整个的Win32 API到处,于是Python就能像C/C++语言一样完全操作整个操作系统了,并且,这还是动态的!!!!

没错,不过多大的工作量啊。。。。。。不过,Python这么流行,总是有人做这样的事情的,于是PyWindows出世了。去安装一个,于是你什么都有了。

>>> import win32api

>>> win32api.MessageBox(0, "Great", "Hello World", 0)

1

这样,就能达到上面全部的效果。。。。。。。。。。。

Python ctypes

如此这般,原来Python还是离不开C啊(虽然Python本身使用C写的)。。。,直到。。。。某年某月ctypes横空出世了,于是,完全不

懂C语言的人,也可以直接用Python来完成这样的工作了。毫无疑问,Python越来越自成体系了,他们的目标是,没有其他语言!-_-!在

Python v3.1.1的文档中如此描述,

ctypes

— A foreign

function library for Python

然后:It can be used to wrap these libraries in pure Python.

注意,他们要的是Pure Python!(我不是想要挑起语言战争。。。。。)

Guido van Rossum开始说,wrap these,in pure Python。。。。不要再用foreign语言,血统不pure的家伙了。

闲话少说,看看ctypes,因为是pure Python嘛,所以看起来很简单,事实上文档也比较详细(当然,还是遗漏了一些细节),下面都以Windows中的Python3.1.1的操作为例:

>>> import ctypes

>>> from ctypes import *

>>> dir(ctypes)

['ARRAY', 'ArgumentError', 'Array', 'BigEndianStructure', 'CDLL', 'CFUNCTYPE', '

DEFAULT_MODE', 'DllCanUnloadNow', 'DllGetClassObject', 'FormatError', 'GetLastEr

ror', 'HRESULT', 'LibraryLoader', 'LittleEndianStructure', 'OleDLL', 'POINTER',

'PYFUNCTYPE', 'PyDLL', 'RTLD_GLOBAL', 'RTLD_LOCAL', 'SetPointerType', 'Structure

', 'Union', 'WINFUNCTYPE', 'WinDLL', 'WinError', '_CFuncPtr', '_FUNCFLAG_CDECL',

'_FUNCFLAG_PYTHONAPI', '_FUNCFLAG_STDCALL', '_FUNCFLAG_USE_ERRNO', '_FUNCFLAG_U

SE_LASTERROR', '_Pointer', '_SimpleCData', '__builtins__', '__doc__', '__file__'

, '__name__', '__package__', '__path__', '__version__', '_c_functype_cache', '_c

alcsize', '_cast', '_cast_addr', '_check_HRESULT', '_check_size', '_ctypes_versi

on', '_dlopen', '_endian', '_memmove_addr', '_memset_addr', '_os', '_pointer_typ

e_cache', '_string_at', '_string_at_addr', '_sys', '_win_functype_cache', '_wstr

ing_at', '_wstring_at_addr', 'addressof', 'alignment', 'byref', 'c_bool', 'c_buf

fer', 'c_byte', 'c_char', 'c_char_p', 'c_double', 'c_float', 'c_int', 'c_int16',

'c_int32', 'c_int64', 'c_int8', 'c_long', 'c_longdouble', 'c_longlong', 'c_shor

t', 'c_size_t', 'c_ubyte', 'c_uint', 'c_uint16', 'c_uint32', 'c_uint64', 'c_uint

8', 'c_ulong', 'c_ulonglong', 'c_ushort', 'c_void_p', 'c_voidp', 'c_wchar', 'c_w

char_p', 'cast', 'cdll', 'create_string_buffer', 'create_unicode_buffer', 'get_e

rrno', 'get_last_error', 'memmove', 'memset', 'oledll', 'pointer', 'py_object',

'pydll', 'pythonapi', 'resize', 'set_conversion_mode', 'set_errno', 'set_last_er

ror', 'sizeof', 'string_at', 'windll', 'wstring_at']

一个这样的小玩意儿包含的东西还真不少啊,可以看到主要包括一些C语言的类型定义。

当你import ctypes的时候,一些动态库已经载入了:

>>> print(windll.kernel32)

>>> print(windll.user32)

>>> print(windll.msvcrt)

直接来使用试试吧,我们最喜欢的自然是Hello World。这里直接调用MessageBox。查查MSDN,MessageBox在User32中,我们调用它。

>>> MessageBox = windll.user32.MessageBoxW

>>> MessageBox(0,"Great","Hello World", 0)

然后,就调用了MessageBox了。。。。。。。。

怎么?晕了?比较一下ctypes库及Python C API吧。。。。于是,K&R哭了。。。。。。。。。。。。。

故事以下图开始

以下图结束:

python ctypes实现api测试_Python与C之间的相互调用(Python C API及Python ctypes库)相关推荐

  1. Python与C之间的相互调用

    Python与C之间的相互调用(Python C API及Python ctypes库) 分类: [Python]2010-01-24 17:58 32468人阅读 评论(11) 收藏 举报 pyth ...

  2. python模拟用户压力测试_Python 工具 Locust 进行负载测试

    Locust 是一个用 Python 编写的开源的负载测试工具. 它允许您针对模拟用户行为的 Web 应用程序编写测试,然后按规模运行测试以帮助查找瓶颈或其他性能问题. 安装 安装是使用 Python ...

  3. wordpress rest api 登录_Python构建RESTful网络服务[Django篇:生成API文档]

    链接:https://pan.baidu.com/s/15Mo9adr4Iw2W-um7WK68jA 提取码:ux79 系列文章介绍 本系列文章将详细介绍将Django官方引导教程中的投票项目改写为R ...

  4. python规定的函数头部_Python基础手册23——函数的调用

    三.函数的调用 Python 语言中调用函数与在其它高级语言中一样, 函数名加上函数运算符(一对小括号). 括号之间是所有可选的参数. 即使一个参数也没有, 小括号也不能省略.函数在调用之前必须先定义 ...

  5. python 函数定义先后是否会影响函数之间的相互调用?(不影响)

    # -*- coding: utf-8 -*- """ @File : 201006_测试是否能将被调用函数写在被调用函数之后.py @Time : 2020/1/6 1 ...

  6. python文件之间的相互调用_「Python 系列」 Python 生成器函数详解

    Python的生成器函数提供了一种强大的机制来管理数据和计算资源,但是对于Python的新手来说,它们不一定直观.在本文中,我将分解生成器的机制,同时还介绍我希望是一个有启发性的示例:用于管理和流传输 ...

  7. c# python 相互调用_【GhPython】Python如何使用“委托”和lambda表达式

    [版权声明] | 作者:月之眼 | 首发于大水牛参数化设计平台 | 如需转载请联系作者 | 如果觉得文章不错,欢迎分享  函数作为参数传入  在python中函数是能作为参数输入函数的.这个有点类似于 ...

  8. Python与C之间的相互调用(Python C API及Python ctypes库)

    2010-01-24 17:58 14237人阅读 评论(11) 收藏 举报 目录(?)[-] Python C API 准备工作: C中内嵌Python 获取返回值 利用C扩展Python Pyth ...

  9. Python与C之间的相互调用(Python C API及Python ctypes库)【转】

    准备工作: 闲话少说,看看Python C API.事实上,Python C API比起Lua的API了来说,清晰了很多,这也符合Pythonic的风格,就算这时Python C API是设计给C语言 ...

最新文章

  1. 百度大脑金秋九月CV盛典,人脸识别新产品及伙伴计划发布会压轴开启
  2. 分布式唯一id:snowflake算法思考
  3. 《JavaScript高效图形编程(修订版)》——第2章 DHTML基础 2.1创建DHTML sprite
  4. Android访问WCF服务(使用json实现参数传递)
  5. 端午小长假--前端基础学起来02与浏览器交互,表单标签
  6. 有哪些大数据处理工具?
  7. C++类型转换基本语法
  8. 惠普打印机只打印一半_惠普打印机如何安装 惠普打印机加墨方法【介绍】
  9. Oracle查询指定表里的触发器
  10. [GNU LD系列 3.3] 简单的链接脚本例程
  11. 腾讯无人车开进硅谷!建团队、招人才,国内放出商务岗位
  12. 2012工行软开中心-广州面试
  13. 鱼眼和全向视图的图像深度学习方法
  14. node 拦截器拦截请求下载电子书以及等待前端渲染操作、浏览器操作
  15. matlab 子函数怎么写,matlab中怎么写函数
  16. U盘,移动硬盘显示显示需要格式化怎么修复
  17. 安卓Zygote详解
  18. 07- Workbench网格划分概述
  19. 推荐几款比较好的手机流量监控软件
  20. ec20 复位命令_Quectel EC20 R2.1 AT指令集(基础部分)未完

热门文章

  1. 项目发布时候出错--项目文件包含 ToolsVersion=12.0
  2. 金融系列4《基本指令》
  3. LeetCode 78 子集 中等难度
  4. 数据库SQL Server 2019安装向导的“功能选择”详细说明(微软官方资料)
  5. c语言不用switch做计算器,超级新手,用switch写了个计算器程序,求指导
  6. java 接口中 常量_讨论:Java 接口当中的 “常量接口”
  7. 2019ug最新版本是多少_NX1847:2019年最新版本,从某种意义上来说,也将是终极版本...
  8. php微信小程序物流进度推送,微信小程序 消息推送php服务器验证实例详解
  9. python字符垂直输出型烟雾机_python+opencv实现水平投影和垂直投影
  10. 淮阴工学院研究生计算机,先鸣论坛第六期/考研加油站(五)|2017届淮阴工学院计算机学院考研最高分王杰和你一起分享他的考研经验...