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

歡迎訪問 生活随笔!

生活随笔

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

python

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

發(fā)布時(shí)間:2025/4/16 python 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python ctypes实现api测试_Python与C之间的相互调用(Python C API及Python ctypes库) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

2010-01-24 17:58 14237人閱讀 評(píng)論(11)

我實(shí)現(xiàn)

Python C API

此部分可以參考我原來的文章《

準(zhǔn)備工作:

閑話少說,看看Python C API。事實(shí)上,Python C

API比起Lua的API了來說,清晰了很多,這也符合Pythonic的風(fēng)格,就算這時(shí)Python

C API是設(shè)計(jì)給C語言使用者使用的,還是這樣的風(fēng)格,比起Lua API那種匯編式的接口,(據(jù)說為了效率,可以直接操作每個(gè)數(shù)據(jù))強(qiáng)了太多了。

要使用Python C API,用普通的二進(jìn)制包是不行的,得下源碼包。這里我用3.1.1的源碼包為例:Source Distribution

Python的源碼在Windows的版本中已經(jīng)完全換到VS2008了,直接用VS2008打開在PCbuild目錄下的工程即可,對(duì)于VS2005及

以前的用戶打開PC目錄下的其他版本工程。我們編譯debug版本的pythoncore會(huì)得到

python31_d.lib,python31_d.dll兩個(gè)文件,需要的頭文件在Include目錄下,還需要將pyconfig.h文件從

PCBuild目錄下拷貝到Include中,(硬要直接指定也可以)這樣準(zhǔn)備工作就已經(jīng)齊了。

Python C API有兩個(gè)方向的使用方式,從C中調(diào)用Python腳本及利用C擴(kuò)展Python。

先講簡(jiǎn)單的從C中調(diào)用Python,也就是常說的在C中內(nèi)嵌Python。

C中內(nèi)嵌Python

新建立一個(gè)工程,首先需要將工作目錄設(shè)置到Python-3.1.1PCbuild中,以獲取到動(dòng)態(tài)庫,至于靜態(tài)庫的包含,Include目錄的指定,那自然也是少不了的。文件中需要包含Python.h文件,這也是必須的。

接口中

Py_Initialize();

Py_Finalize();

一對(duì)的調(diào)用是必須的,一個(gè)用于初始化Python的動(dòng)態(tài)庫,一個(gè)用于釋放。釋放時(shí)會(huì)輸出[31818 refs],意義不明。

PyRun_SimpleString

可用于執(zhí)行簡(jiǎn)單的Python語句。如下:

#include

"python.h"

int

main(int

argc, char

* argv[])

{

Py_Initialize();

PyRun_SimpleString("print(

"

Hello World

"

)"

);

Py_Finalize();

system("PAUSE"

);

return

0

;

}

此時(shí),輸出為:

Hello World

[31829 refs]

請(qǐng)按任意鍵繼續(xù). . .

此時(shí)可以執(zhí)行一些Python語句了,并且,特別需要注意的是,在一個(gè)Py_Initialize();與Py_Finalize();之間,Python語句執(zhí)行是在同一個(gè)執(zhí)行環(huán)境中,不懂什么意思?看個(gè)示例就知道了。

int

main(int

argc, char

* argv[])

{

Py_Initialize();

PyRun_SimpleString("str =

"

Hello World

"

"

);

PyRun_SimpleString("print(str)"

);

Py_Finalize();

system("PAUSE"

);

return

0

;

}

此例與上例輸出是一樣的,懂我的意思了吧?意思就是以前執(zhí)行的語句對(duì)后面的語句是有效的,相當(dāng)于在同一個(gè)交互式命令行中順序執(zhí)行語句。

獲取返回值

PyRun_SimpleString有的缺點(diǎn),文檔中的描述是:

Returns 0

on success or

-1

if an exception was

raised.

那么你就無法在Python及C語言中傳遞任何信息。我們需要高級(jí)點(diǎn)的函數(shù)才行。

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

就是干這個(gè)的。

但是需要注意的是此函數(shù)的一些參數(shù)的獲取,按照想當(dāng)然的給他們置空可是不行的,如下例所示:

#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

;

}

這里我利用了一個(gè)知識(shí),那就是

PyRun_SimpleString實(shí)際是將所有的代碼都放在

__main__

模塊中運(yùn)行,注意啊,沒有導(dǎo)入正確的模塊及其dict,你會(huì)運(yùn)行失敗,失敗的很慘。至此,C語言已經(jīng)于Python來了個(gè)交互了。

呵呵,突然覺得深入下去就沒有盡頭了。。。。。。。還是點(diǎn)到為止吧。

稍微深入點(diǎn)的可以去看《Programming Python》一書。在啄木鳥

上有此書及一些譯文。Part VI: Integration 部分Chapter 23. Embedding Python,有相關(guān)的知識(shí)。

利用C擴(kuò)展Python

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

這里也只能開個(gè)頭了,最多告訴你,其實(shí),這些都沒有什么難的。稍微復(fù)雜點(diǎn)的情況《#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);

}

這個(gè)例子包含了全部C語言為Python寫擴(kuò)展時(shí)的基本信息:

1.PyInit_example是最后的出口,其中需要注意的是example不僅僅代表example的意思,還代表了最后生成的庫會(huì)用example命名,也就是你調(diào)用此庫會(huì)需要使用

import example

的形式。

2.static

struct

PyModuleDef examplemodule的存在也是必須的,指定了整個(gè)模塊的信息,比如上面

的"example module doc string",模塊的說明文字。每個(gè)參數(shù)的含義上面已經(jīng)有些演示了。

全部?jī)?nèi)容可以參考文檔中關(guān)于PyModuleDef的說明

3.example_methods是一個(gè)函數(shù)列表,事實(shí)上表示此模塊中含有的函數(shù)。此例中僅含有

foo一個(gè)函數(shù)。

static

PyObject *

ex_foo(PyObject *self, PyObject *args)

{

printf("Hello, world

n

"

);

Py_INCREF(Py_None);

return

Py_None;

}

就是整個(gè)函數(shù)的具體實(shí)現(xiàn)了,此函數(shù)表示輸出"Hello, world",還是hello world。。。。。。。。這個(gè)world還真忙啊。。。。天天有人say hello。

這個(gè)Python本身附帶的例子有點(diǎn)太簡(jiǎn)單了,我給出一個(gè)稍微復(fù)雜點(diǎn)的例子,還是我最喜歡的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);

}

需要注意的還是需要注意,唯一有點(diǎn)區(qū)別的是這里我有從Python中傳進(jìn)來的參數(shù)及從C中傳出去的返回值了。

PyArg_ParseTuple

用于解析參數(shù)

Py_BuildValue 用于構(gòu)建一個(gè)Python的值返回

他們的構(gòu)建和解析形式有點(diǎn)類似于sprintf等C常見的形式,可是每個(gè)字符代表的東西不一定一樣,需要注意,文檔中比較詳細(xì),此例中展示的是String及int的轉(zhuǎn)換。

以生成動(dòng)態(tài)庫的方式編譯此文件后,并指定為Win32API.pyd文件,然后將其拷貝到Python_d所在的目錄(用Python3.1.1源代碼生成的調(diào)試版本Python),此時(shí)import會(huì)首先查找*_d.pyd形式的動(dòng)態(tài)庫,不然只會(huì)搜索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的強(qiáng)大。。。。。。。。。。。。。此時(shí)MessageBox已經(jīng)在Win32API中了,直接調(diào)用吧。我這里忽略了窗口的句柄,需要注意。

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

此時(shí)你會(huì)想,太強(qiáng)大了,我要將整個(gè)的Win32 API到處,于是Python就能像C/C++語言一樣完全操作整個(gè)操作系統(tǒng)了,并且,這還是動(dòng)態(tài)的!!!!

沒錯(cuò),不過多大的工作量啊。。。。。。不過,Python這么流行,總是有人做這樣的事情的,于是PyWindows出世了。去安裝一個(gè),于是你什么都有了。

>>> import win32api

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

1

這樣,就能達(dá)到上面全部的效果。。。。。。。。。。。

Python ctypes

如此這般,原來Python還是離不開C啊(雖然Python本身使用C寫的)。。。,直到。。。。某年某月ctypes橫空出世了,于是,完全不

懂C語言的人,也可以直接用Python來完成這樣的工作了。毫無疑問,Python越來越自成體系了,他們的目標(biāo)是,沒有其他語言!-_-!在

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

ctypes

— A foreign

function library for Python

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

注意,他們要的是Pure Python!(我不是想要挑起語言戰(zhàn)爭(zhēng)。。。。。)

Guido van Rossum開始說,wrap these,in pure Python。。。。不要再用foreign語言,血統(tǒng)不pure的家伙了。

閑話少說,看看ctypes,因?yàn)槭莗ure Python嘛,所以看起來很簡(jiǎn)單,事實(shí)上文檔也比較詳細(xì)(當(dāng)然,還是遺漏了一些細(xì)節(jié)),下面都以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']

一個(gè)這樣的小玩意兒包含的東西還真不少啊,可以看到主要包括一些C語言的類型定義。

當(dāng)你import ctypes的時(shí)候,一些動(dòng)態(tài)庫已經(jīng)載入了:

>>> print(windll.kernel32)

>>> print(windll.user32)

>>> print(windll.msvcrt)

直接來使用試試吧,我們最喜歡的自然是Hello World。這里直接調(diào)用MessageBox。查查MSDN,MessageBox在User32中,我們調(diào)用它。

>>> MessageBox = windll.user32.MessageBoxW

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

然后,就調(diào)用了MessageBox了。。。。。。。。

怎么?暈了?比較一下ctypes庫及Python C API吧。。。。于是,K&R哭了。。。。。。。。。。。。。

故事以下圖開始

以下圖結(jié)束:

總結(jié)

以上是生活随笔為你收集整理的python ctypes实现api测试_Python与C之间的相互调用(Python C API及Python ctypes库)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

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