15.17。 |
ctypes類型 | C型 | Python類型 |
---|---|---|
c_bool |
_Bool |
布爾(1) |
c_char |
char |
1個(gè)字符的字符串 |
c_wchar |
wchar_t |
1個(gè)字符的unicode字符串 |
c_byte |
char |
INT /長 |
c_ubyte |
unsigned char |
INT /長 |
c_short |
short |
INT /長 |
c_ushort |
unsigned short |
INT /長 |
c_int |
int |
INT /長 |
c_uint |
unsigned int |
INT /長 |
c_long |
long |
INT /長 |
c_ulong |
unsigned long |
INT /長 |
c_longlong |
__int64 要么 long long |
INT /長 |
c_ulonglong |
unsigned __int64 要么 unsigned long long |
INT /長 |
c_float |
float |
浮動(dòng) |
c_double |
double |
浮動(dòng) |
c_longdouble |
long double |
浮動(dòng) |
c_char_p |
char * (NUL終止) |
字符串或 None |
c_wchar_p |
wchar_t * (NUL終止) |
unicode或 None |
c_void_p |
void * |
int / long或 None |
構(gòu)造函數(shù)接受具有真值的任何對象。
所有這些類型都可以通過使用正確類型和值的可選初始化程序調(diào)用它們來創(chuàng)建:
- >>> 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 i
- c_long(42)
- >>> print i.value
- 42
- >>> i.value = -99
- >>> print i.value
- -99
- >>>
分配一個(gè)新的值,將指針類型的實(shí)例c_char_p
, c_wchar_p
以及c_void_p
改變所述存儲(chǔ)器位置它們指向,而不是內(nèi)容的內(nèi)存塊(當(dāng)然不是,因?yàn)镻ython字符串是不可變的):
- >>> s = "Hello, World"
- >>> c_s = c_char_p(s)
- >>> print c_s
- c_char_p('Hello, World')
- >>> c_s.value = "Hi, there"
- >>> print c_s
- c_char_p('Hi, there')
- >>> print s # first string is unchanged
- Hello, World
- >>>
但是,您應(yīng)該小心,不要將它們傳遞給期望指向可變內(nèi)存的函數(shù)。如果你需要可變的內(nèi)存塊,ctypes有一個(gè)create_string_buffer()
以各種方式創(chuàng)建它們的 函數(shù)。可以使用raw
屬性訪問(或更改)當(dāng)前內(nèi)存塊內(nèi)容; 如果要以NUL終止字符串的形式訪問它,請使用以下value
屬性:
- >>> 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'
- >>>
該create_string_buffer()
函數(shù)替換了c_buffer()
函數(shù)(仍可作為別名使用),以及c_string()
早期ctypes版本中的函數(shù)。要?jiǎng)?chuàng)建包含C類型的unicode字符的可變內(nèi)存塊,請wchar_t
使用該 create_unicode_buffer()
函數(shù)。
需要注意的是的printf打印到實(shí)際的標(biāo)準(zhǔn)輸出通道,不給 sys.stdout
,所以這些例子只是在控制臺(tái)提示符下運(yùn)行,而不是從內(nèi)IDLE或PythonWin的:
- >>> printf = libc.printf
- >>> printf("Hello, %s\n", "World!")
- Hello, World!
- 14
- >>> printf("Hello, %S\n", u"World!")
- Hello, World!
- 14
- >>> printf("%d bottles of beer\n", 42)
- 42 bottles of beer
- 19
- >>> printf("%f bottles of beer\n", 42.5)
- Traceback (most recent call last):
- File "<stdin>", line 1, in <module>
- ArgumentError: argument 2: exceptions.TypeError: Don't know how to convert parameter 2
- >>>
如前所述,除了整數(shù),字符串和unicode字符串之外的所有Python類型都必須包裝在相應(yīng)的ctypes
類型中,以便它們可以轉(zhuǎn)換為所需的C數(shù)據(jù)類型:
- >>> printf("An int %d, a double %f\n", 1234, c_double(3.14))
- An int 1234, a double 3.140000
- 31
- >>>
您還可以自定義ctypes
參數(shù)轉(zhuǎn)換,以允許將您自己的類的實(shí)例用作函數(shù)參數(shù)。 ctypes
查找 _as_parameter_
屬性并將其用作函數(shù)參數(shù)。當(dāng)然,它必須是整數(shù),字符串或unicode之一:
- >>> class Bottles(object):
- ... def __init__(self, number):
- ... self._as_parameter_ = number
- ...
- >>> bottles = Bottles(42)
- >>> printf("%d bottles of beer\n", bottles)
- 42 bottles of beer
- 19
- >>>
如果您不想將實(shí)例的數(shù)據(jù)存儲(chǔ)在_as_parameter_
實(shí)例變量中,則可以定義property()
使數(shù)據(jù)可用的數(shù)據(jù)。
可以通過設(shè)置argtypes
屬性來指定從DLL導(dǎo)出的函數(shù)所需的參數(shù)類型。
argtypes
必須是一系列C數(shù)據(jù)類型(這里的printf
函數(shù)可能不是一個(gè)很好的例子,因?yàn)樗Q于格式字符串需要一個(gè)可變數(shù)字和不同類型的參數(shù),另一方面,這對于試驗(yàn)這個(gè)特性非常方便) :
- >>> printf.argtypes = [c_char_p, c_char_p, c_int, c_double]
- >>> printf("String '%s', Int %d, Double %f\n", "Hi", 10, 2.2)
- String 'Hi', Int 10, Double 2.200000
- 37
- >>>
指定格式可以防止不兼容的參數(shù)類型(就像C函數(shù)的原型一樣),并嘗試將參數(shù)轉(zhuǎn)換為有效類型:
- >>> printf("%d %d %d", 1, 2, 3)
- Traceback (most recent call last):
- File "<stdin>", line 1, in <module>
- ArgumentError: argument 2: exceptions.TypeError: wrong type
- >>> printf("%s %d %f\n", "X", 2, 3)
- X 2 3.000000
- 13
- >>>
如果已經(jīng)定義了自己傳遞給函數(shù)調(diào)用的from_param()
類,則必須為它們實(shí)現(xiàn)一個(gè)類方法,以便能夠在argtypes
序列中使用它們。本from_param()
類方法接收傳給函數(shù)的Python對象,它做一個(gè)類型檢測,或者是需要確保這個(gè)對象是可接受的,然后返回對象本身,它_as_parameter_
不管你想傳遞的C函數(shù)屬性,或在這種情況下的論點(diǎn)。同樣,結(jié)果應(yīng)該是整數(shù),字符串,unicode,ctypes
實(shí)例或具有_as_parameter_
屬性的對象 。
默認(rèn)情況下,假定函數(shù)返回C int
類型??梢酝ㄟ^設(shè)置restype
函數(shù)對象的屬性來指定其他返回類型。
這是一個(gè)更高級的示例,它使用strchr
函數(shù),它需要一個(gè)字符串指針和一個(gè)char,并返回一個(gè)指向字符串的指針:
- >>> strchr = libc.strchr
- >>> strchr("abcdef", ord("d"))
- 8059983
- >>> 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
- >>>
如果要避免ord("x")
上面的調(diào)用,可以設(shè)置 argtypes
屬性,第二個(gè)參數(shù)將從單個(gè)字符Python字符串轉(zhuǎn)換為C字符:
- >>> strchr.restype = c_char_p
- >>> strchr.argtypes = [c_char_p, c_char]
- >>> strchr("abcdef", "d")
- 'def'
- >>> strchr("abcdef", "def")
- Traceback (most recent call last):
- File "<stdin>", line 1, in <module>
- ArgumentError: argument 2: exceptions.TypeError: one character string expected
- >>> print strchr("abcdef", "x")
- None
- >>> strchr("abcdef", "d")
- 'def'
- >>>
restype
如果外部函數(shù)返回一個(gè)整數(shù),您還可以使用可調(diào)用的Python對象(例如函數(shù)或類)作為屬性。將使用C函數(shù)返回的整數(shù)調(diào)用callable ,并且此調(diào)用的結(jié)果將用作函數(shù)調(diào)用的結(jié)果。這對于檢查錯(cuò)誤返回值并自動(dòng)引發(fā)異常非常有用:
- >>> GetModuleHandle = windll.kernel32.GetModuleHandleA
- >>> def ValidHandle(value):
- ... if value == 0:
- ... raise WinError()
- ... return value
- ...
- >>>
- >>> GetModuleHandle.restype = ValidHandle
- >>> GetModuleHandle(None)
- 486539264
- >>> GetModuleHandle("something silly")
- Traceback (most recent call last):
- File "<stdin>", line 1, in <module>
- File "<stdin>", line 3, in ValidHandle
- WindowsError: [Errno 126] The specified module could not be found.
- >>>
WinError
是一個(gè)函數(shù),它將調(diào)用Windows FormatMessage()
api來獲取錯(cuò)誤代碼的字符串表示,并返回一個(gè)異常。 WinError
采用可選的錯(cuò)誤代碼參數(shù),如果沒有使用,則調(diào)用它 GetLastError()
來檢索它。
請注意,通過該errcheck
屬性可以使用更強(qiáng)大的錯(cuò)誤檢查機(jī)制; 有關(guān)詳細(xì)信息,請參閱參考手冊
有時(shí),C api函數(shù)需要將指向數(shù)據(jù)類型的指針作為參數(shù),可能要寫入相應(yīng)的位置,或者數(shù)據(jù)太大而無法通過值傳遞。這也稱為通過引用傳遞參數(shù)。
ctypes
導(dǎo)出byref()
用于通過引用傳遞參數(shù)的函數(shù)。使用該pointer()
函數(shù)可以實(shí)現(xiàn)相同的效果 ,但是pointer()
由于它構(gòu)造了一個(gè)真正的指針對象,所以工作量更大,因此byref()
如果您不需要Python本身的指針對象,則使用它會(huì)更快:
- >>> 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'
- >>>
結(jié)構(gòu)和聯(lián)合必須從導(dǎo)出Structure
和Union
其中所定義的基類ctypes
模塊。每個(gè)子類都必須定義一個(gè)_fields_
屬性。 _fields_
必須是2元組的列表 ,包含字段名稱和字段類型。
字段類型必須是ctypes
類型c_int
或任何其他派生ctypes
類型:結(jié)構(gòu),聯(lián)合,數(shù)組,指針。
下面是一個(gè)POINT結(jié)構(gòu)的簡單示例,它包含兩個(gè)名為x和y的整數(shù) ,還顯示了如何在構(gòu)造函數(shù)中初始化結(jié)構(gòu):
- >>> from ctypes import *
- >>> class POINT(Structure):
- ... _fields_ = [("x", c_int),
- ... ("y", c_int)]
- ...
- >>> point = POINT(10, 20)
- >>> print point.x, point.y
- 10 20
- >>> point = POINT(y=5)
- >>> print point.x, point.y
- 0 5
- >>> POINT(1, 2, 3)
- Traceback (most recent call last):
- File "<stdin>", line 1, in <module>
- ValueError: too many initializers
- >>>
但是,您可以構(gòu)建更復(fù)雜的結(jié)構(gòu)。通過將結(jié)構(gòu)用作字段類型,結(jié)構(gòu)本身可以包含其他結(jié)構(gòu)。
這是一個(gè)RECT結(jié)構(gòu),它包含兩個(gè)名為upperleft和 lowerright的POINT:
- >>> class RECT(Structure):
- ... _fields_ = [("upperleft", POINT),
- ... ("lowerright", POINT)]
- ...
- >>> rc = RECT(point)
- >>> print rc.upperleft.x, rc.upperleft.y
- 0 5
- >>> print rc.lowerright.x, rc.lowerright.y
- 0 0
- >>>
嵌套結(jié)構(gòu)也可以通過以下幾種方式在構(gòu)造函數(shù)中初始化:
- >>> r = RECT(POINT(1, 2), POINT(3, 4))
- >>> r = RECT((1, 2), (3, 4))
字段描述符 S可從被檢索類,它們可用于調(diào)試有用,因?yàn)樗鼈兛梢蕴峁┯杏玫男畔ⅲ?/p>
- >>> print POINT.x
- <Field type=c_long, ofs=0, size=4>
- >>> print POINT.y
- <Field type=c_long, ofs=4, size=4>
- >>>
警告
ctypes
不支持通過值將具有位字段的聯(lián)合或結(jié)構(gòu)傳遞給函數(shù)。雖然這可能適用于32位x86,但是不能保證庫在一般情況下工作。具有位字段的聯(lián)合和結(jié)構(gòu)應(yīng)始終通過指針傳遞給函數(shù)。
默認(rèn)情況下,Structure和Union字段的對齊方式與C編譯器的方式相同??梢酝ㄟ^_pack_
在子類定義中指定類屬性來覆蓋此行為 。必須將其設(shè)置為正整數(shù),并指定字段的最大對齊方式。這也是MSVC中的做法。#pragma pack(n)
ctypes
使用結(jié)構(gòu)和聯(lián)合的本機(jī)字節(jié)順序。要建立與非本地字節(jié)順序結(jié)構(gòu),你可以使用一個(gè) BigEndianStructure
,LittleEndianStructure
, BigEndianUnion
,和LittleEndianUnion
基類。這些類不能包含指針字段。
可以創(chuàng)建包含位字段的結(jié)構(gòu)和聯(lián)合。位字段僅適用于整數(shù)字段,位寬指定為_fields_
元組中的第三項(xiàng):
- >>> class Int(Structure):
- ... _fields_ = [("first_16", c_int, 16),
- ... ("second_16", c_int, 16)]
- ...
- >>> print Int.first_16
- <Field type=c_long, ofs=0:0, bits=16>
- >>> print Int.second_16
- <Field type=c_long, ofs=0:16, bits=16>
- >>>
數(shù)組是序列,包含固定數(shù)量的相同類型的實(shí)例。
創(chuàng)建數(shù)組類型的推薦方法是將數(shù)據(jù)類型與正整數(shù)相乘:
TenPointsArrayType = POINT * 10
這是一個(gè)有點(diǎn)人為的數(shù)據(jù)類型的例子,一個(gè)包含4個(gè)POINT和其他東西的結(jié)構(gòu):
- >>> from ctypes import *
- >>> class POINT(Structure):
- ... _fields_ = ("x", c_int), ("y", c_int)
- ...
- >>> class MyStruct(Structure):
- ... _fields_ = [("a", c_int),
- ... ("b", c_float),
- ... ("point_array", POINT * 4)]
- >>>
- >>> print len(MyStruct().point_array)
- 4
- >>>
通過調(diào)用類以通常的方式創(chuàng)建實(shí)例:
- arr = TenPointsArrayType()
- for pt in arr:
- print pt.x, pt.y
上面的代碼打印了一系列行,因?yàn)閿?shù)組內(nèi)容被初始化為零。0 0
也可以指定正確類型的初始化器:
- >>> from ctypes import *
- >>> TenIntegers = c_int * 10
- >>> ii = TenIntegers(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
- >>> print ii
- <c_long_Array_10 object at 0x...>
- >>> for i in ii: print i,
- ...
- 1 2 3 4 5 6 7 8 9 10
- >>>
通過pointer()
在ctypes
類型上調(diào)用函數(shù) 來創(chuàng)建指針實(shí)例:
- >>> from ctypes import *
- >>> i = c_int(42)
- >>> pi = pointer(i)
- >>>
指針實(shí)例有一個(gè)contents
屬性,它返回指針指向的i
對象,上面的對象:
- >>> pi.contents
- c_long(42)
- >>>
注意,ctypes
沒有OOR(原始對象返回),每次檢索屬性時(shí)它都會(huì)構(gòu)造一個(gè)新的等效對象:
- >>> pi.contents is i
- False
- >>> pi.contents is pi.contents
- False
- >>>
將另一個(gè)c_int
實(shí)例分配給指針的contents屬性會(huì)導(dǎo)致指針指向存儲(chǔ)它的內(nèi)存位置:
- >>> i = c_int(99)
- >>> pi.contents = i
- >>> pi.contents
- c_long(99)
- >>>
指針實(shí)例也可以用整數(shù)索引:
- >>> pi[0]
- 99
- >>>
分配整數(shù)索引會(huì)更改指向的值:
- >>> print i
- c_long(99)
- >>> pi[0] = 22
- >>> print i
- c_long(22)
- >>>
也可以使用不同于0的索引,但您必須知道自己在做什么,就像在C中一樣:您可以訪問或更改任意內(nèi)存位置。通常,如果從C函數(shù)接收指針,則只使用此功能,并且您知道指針實(shí)際指向的是數(shù)組而不是單個(gè)項(xiàng)。
在幕后,該pointer()
函數(shù)不僅僅是創(chuàng)建指針實(shí)例,還必須首先創(chuàng)建指針類型。這是通過POINTER()
接受任何ctypes
類型的函數(shù)完成的,并返回一個(gè)新類型:
- >>> PI = POINTER(c_int)
- >>> PI
- <class 'ctypes.LP_c_long'>
- >>> PI(42)
- Traceback (most recent call last):
- File "<stdin>", line 1, in <module>
- TypeError: expected c_long instead of int
- >>> PI(c_int(42))
- <ctypes.LP_c_long object at 0x...>
- >>>
調(diào)用不帶參數(shù)的指針類型會(huì)創(chuàng)建NULL
指針。 NULL
指針有一個(gè)False
布爾值:
- >>> null_ptr = POINTER(c_int)()
- >>> print bool(null_ptr)
- False
- >>>
ctypes
檢查NULL
何時(shí)解除引用指針(但解除引用無效的非NULL
指針會(huì)使Python崩潰):
- >>> null_ptr[0]
- Traceback (most recent call last):
- ....
- ValueError: NULL pointer access
- >>>
- >>> null_ptr[0] = 1234
- Traceback (most recent call last):
- ....
- ValueError: NULL pointer access
- >>>
通常,ctypes會(huì)進(jìn)行嚴(yán)格的類型檢查。這意味著,如果您 POINTER(c_int)
在argtypes
函數(shù)列表中或在結(jié)構(gòu)定義中具有成員字段的類型,則只接受完全相同類型的實(shí)例。此規(guī)則有一些例外,其中ctypes接受其他對象。例如,您可以傳遞兼容的數(shù)組實(shí)例而不是指針類型。因此,對于POINTER(c_int)
,ctypes接受一個(gè)c_int數(shù)組:
- >>> class Bar(Structure):
- ... _fields_ = [("count", c_int), ("values", POINTER(c_int))]
- ...
- >>> bar = Bar()
- >>> bar.values = (c_int * 3)(1, 2, 3)
- >>> bar.count = 3
- >>> for i in range(bar.count):
- ... print bar.values[i]
- ...
- 1
- 2
- 3
- >>>
此外,如果函數(shù)參數(shù)顯式聲明為指針類型(例如POINTER(c_int)
)in argtypes
,則可以將指向類型的對象(c_int
在本例中)傳遞給函數(shù)。ctypes將自動(dòng)應(yīng)用所需的byref()
轉(zhuǎn)換。
要將POINTER類型字段設(shè)置為NULL
,您可以指定None
:
- >>> bar.values = None
- >>>
有時(shí)您會(huì)遇到不兼容類型的實(shí)例。在C中,您可以將一種類型轉(zhuǎn)換為另一種類型。 ctypes
提供cast()
可以以相同方式使用的功能。Bar
上面定義的結(jié)構(gòu)接受 其字段的POINTER(c_int)
指針或c_int
數(shù)組values
,但不接受其他類型的實(shí)例:
- >>> bar.values = (c_byte * 4)()
- Traceback (most recent call last):
- File "<stdin>", line 1, in <module>
- TypeError: incompatible types, c_byte_Array_4 instance instead of LP_c_long instance
- >>>
對于這些情況,該cast()
功能很方便,cast還支持將python中的id(obj)即對象地址還原為對象
該cast()
函數(shù)可用于將ctypes實(shí)例轉(zhuǎn)換為指向不同ctypes數(shù)據(jù)類型的指針。 cast()
采用兩個(gè)參數(shù),一個(gè)或者可以轉(zhuǎn)換為某種指針的ctypes對象,以及一個(gè)ctypes指針類型。它返回第二個(gè)參數(shù)的實(shí)例,它引用與第一個(gè)參數(shù)相同的內(nèi)存塊:
- >>> a = (c_byte * 4)()
- >>> cast(a, POINTER(c_int))
- <ctypes.LP_c_long object at ...>
- >>>
所以,cast()
可以用來分配給結(jié)構(gòu)的values
字段Bar
:
- >>> bar = Bar()
- >>> bar.values = cast((c_byte * 4)(), POINTER(c_int))
- >>> print bar.values[0]
- 0
- >>>
不完整類型是其成員尚未指定的結(jié)構(gòu),聯(lián)合或數(shù)組。在C中,它們由前向聲明指定,后面將定義:
- struct cell; /* forward declaration */
- struct cell {
- char *name;
- struct cell *next;
- };
直接轉(zhuǎn)換為ctypes代碼就是這樣,但它不起作用:
- >>> class cell(Structure):
- ... _fields_ = [("name", c_char_p),
- ... ("next", POINTER(cell))]
- ...
- Traceback (most recent call last):
- File "<stdin>", line 1, in <module>
- File "<stdin>", line 2, in cell
- NameError: name 'cell' is not defined
- >>>
因?yàn)閚ew 語句本身不可用。在,我們可以 在類語句之后定義類并設(shè)置屬性:class cell
ctypes
cell
_fields_
- >>> from ctypes import *
- >>> class cell(Structure):
- ... pass
- ...
- >>> cell._fields_ = [("name", c_char_p),
- ... ("next", POINTER(cell))]
- >>>
讓我們試試吧。我們創(chuàng)建了兩個(gè)實(shí)例cell
,并讓它們相互指向,最后跟隨指針鏈幾次:
- >>> c1 = cell()
- >>> c1.name = "foo"
- >>> c2 = cell()
- >>> c2.name = "bar"
- >>> c1.next = pointer(c2)
- >>> c2.next = pointer(c1)
- >>> p = c1
- >>> for i in range(8):
- ... print p.name,
- ... p = p.next[0]
- ...
- foo bar foo bar foo bar foo bar
- >>>
ctypes
允許從Python callables創(chuàng)建C可調(diào)用函數(shù)指針。這些有時(shí)稱為回調(diào)函數(shù)。
首先,您必須為回調(diào)函數(shù)創(chuàng)建一個(gè)類,該類知道調(diào)用約定,返回類型以及此函數(shù)將接收的參數(shù)的數(shù)量和類型。
CFUNCTYPE工廠函數(shù)使用普通的cdecl調(diào)用約定為回調(diào)函數(shù)創(chuàng)建類型,在Windows上,WINFUNCTYPE工廠函數(shù)使用stdcall調(diào)用約定為回調(diào)函數(shù)創(chuàng)建類型。
這兩個(gè)工廠函數(shù)都以結(jié)果類型作為第一個(gè)參數(shù)調(diào)用,而回調(diào)函數(shù)將期望的參數(shù)類型作為其余參數(shù)。
我將在這里展示一個(gè)使用標(biāo)準(zhǔn)C庫qsort()
函數(shù)的示例,它用于在回調(diào)函數(shù)的幫助下對項(xiàng)目進(jìn)行排序。 qsort()
將用于對整數(shù)數(shù)組進(jìn)行排序:
- >>> IntArray5 = c_int * 5
- >>> ia = IntArray5(5, 1, 7, 33, 99)
- >>> qsort = libc.qsort
- >>> qsort.restype = None
- >>>
qsort()
必須使用指向要排序的數(shù)據(jù)的指針,數(shù)據(jù)數(shù)組中的項(xiàng)數(shù),一個(gè)項(xiàng)的大小以及指向比較函數(shù)(回調(diào))的指針來調(diào)用。然后使用兩個(gè)指向項(xiàng)目的指針調(diào)用回調(diào),如果第一個(gè)項(xiàng)目小于第二個(gè)項(xiàng)目,它必須返回一個(gè)負(fù)整數(shù),如果它們相等則返回零,然后返回一個(gè)正整數(shù)。
所以我們的回調(diào)函數(shù)接收指向整數(shù)的指針,并且必須返回一個(gè)整數(shù)。首先我們type
為回調(diào)函數(shù)創(chuàng)建:
- >>> CMPFUNC = CFUNCTYPE(c_int, POINTER(c_int), POINTER(c_int))
- >>>
對于回調(diào)函數(shù)的第一個(gè)實(shí)現(xiàn),我們只是打印我們得到的參數(shù),并返回0(增量開發(fā);-):
- >>> def py_cmp_func(a, b):
- ... print "py_cmp_func", a, b
- ... return 0
- ...
- >>>
創(chuàng)建C可調(diào)用回調(diào):
- >>> cmp_func = CMPFUNC(py_cmp_func)
- >>>
我們準(zhǔn)備好了:
- >>> qsort(ia, len(ia), sizeof(c_int), cmp_func)
- py_cmp_func <ctypes.LP_c_long object at 0x00...> <ctypes.LP_c_long object at 0x00...>
- py_cmp_func <ctypes.LP_c_long object at 0x00...> <ctypes.LP_c_long object at 0x00...>
- py_cmp_func <ctypes.LP_c_long object at 0x00...> <ctypes.LP_c_long object at 0x00...>
- py_cmp_func <ctypes.LP_c_long object at 0x00...> <ctypes.LP_c_long object at 0x00...>
- py_cmp_func <ctypes.LP_c_long object at 0x00...> <ctypes.LP_c_long object at 0x00...>
- py_cmp_func <ctypes.LP_c_long object at 0x00...> <ctypes.LP_c_long object at 0x00...>
- py_cmp_func <ctypes.LP_c_long object at 0x00...> <ctypes.LP_c_long object at 0x00...>
- py_cmp_func <ctypes.LP_c_long object at 0x00...> <ctypes.LP_c_long object at 0x00...>
- py_cmp_func <ctypes.LP_c_long object at 0x00...> <ctypes.LP_c_long object at 0x00...>
- py_cmp_func <ctypes.LP_c_long object at 0x00...> <ctypes.LP_c_long object at 0x00...>
- >>>
我們知道如何訪問指針的內(nèi)容,所以讓我們重新定義我們的回調(diào):
- >>> def py_cmp_func(a, b):
- ... print "py_cmp_func", a[0], b[0]
- ... return 0
- ...
- >>> cmp_func = CMPFUNC(py_cmp_func)
- >>>
以下是我們在Windows上獲得的內(nèi)容:
- >>> qsort(ia, len(ia), sizeof(c_int), cmp_func)
- py_cmp_func 7 1
- py_cmp_func 33 1
- py_cmp_func 99 1
- py_cmp_func 5 1
- py_cmp_func 7 5
- py_cmp_func 33 5
- py_cmp_func 99 5
- py_cmp_func 7 99
- py_cmp_func 33 99
- py_cmp_func 7 33
- >>>
很有趣的是,在linux上,sort函數(shù)看起來效率更高,它做的比較少:
- >>> qsort(ia, len(ia), sizeof(c_int), cmp_func)
- py_cmp_func 5 1
- py_cmp_func 33 99
- py_cmp_func 7 33
- py_cmp_func 5 7
- py_cmp_func 1 7
- >>>
啊,我們差不多完成了!最后一步是實(shí)際比較這兩個(gè)項(xiàng)并返回一個(gè)有用的結(jié)果:
- >>> def py_cmp_func(a, b):
- ... print "py_cmp_func", a[0], b[0]
- ... return a[0] - b[0]
- ...
- >>>
最終在Windows上運(yùn)行:
- >>> qsort(ia, len(ia), sizeof(c_int), CMPFUNC(py_cmp_func))
- py_cmp_func 33 7
- py_cmp_func 99 33
- py_cmp_func 5 99
- py_cmp_func 1 99
- py_cmp_func 33 7
- py_cmp_func 1 33
- py_cmp_func 5 33
- py_cmp_func 5 7
- py_cmp_func 1 7
- py_cmp_func 5 1
- >>>
在Linux上:
- >>> qsort(ia, len(ia), sizeof(c_int), CMPFUNC(py_cmp_func))
- py_cmp_func 5 1
- py_cmp_func 33 99
- py_cmp_func 7 33
- py_cmp_func 1 7
- py_cmp_func 5 7
- >>>
很有趣的是,Windows qsort()
功能需要比Linux版本更多的比較!
我們可以輕松檢查,我們的數(shù)組現(xiàn)在排序:
- >>> for i in ia: print i,
- ...
- 1 5 7 33 99
- >>>
注意
CFUNCTYPE()
只要從C代碼中使用對象,請確保保留對對象的引用。ctypes
沒有,如果你不這樣做,它們可能被垃圾收集,在回調(diào)時(shí)崩潰你的程序。
另外,請注意,如果在Python控件之外創(chuàng)建的線程中調(diào)用回調(diào)函數(shù)(例如,通過調(diào)用回調(diào)的外部代碼),ctypes會(huì)在每次調(diào)用時(shí)創(chuàng)建一個(gè)新的虛擬Python線程。這種行為是對大多數(shù)的目的是正確的,但它意味著存儲(chǔ)的值threading.local
將不會(huì)在不同的回調(diào)生存,即使這些電話是從同一個(gè)C的線。
一些共享庫不僅導(dǎo)出函數(shù),還導(dǎo)出變量。Python庫本身的一個(gè)示例是Py_OptimizeFlag
,一個(gè)設(shè)置為0,1或2的整數(shù),具體取決于啟動(dòng)時(shí)給出的-O
或-OO
標(biāo)志。
ctypes
可以使用in_dll()
類型的類方法訪問這樣的值。 pythonapi是一個(gè)預(yù)定義的符號(hào),可以訪問Python C api:
- >>> opt_flag = c_int.in_dll(pythonapi, "Py_OptimizeFlag")
- >>> print opt_flag
- c_long(0)
- >>>
如果解釋器已經(jīng)啟動(dòng)-O
,則樣本將打印c_long(1)
,或者c_long(2)
如果-OO
已經(jīng)指定。
一個(gè)擴(kuò)展示例也演示了指針的使用,可以訪問PyImport_FrozenModules
Python導(dǎo)出的 指針。
引用Python文檔:此指針初始化為指向“struct _frozen”記錄的數(shù)組,由其成員全部為NULL或零的記錄終止。導(dǎo)入凍結(jié)模塊時(shí),將在此表中搜索它。第三方代碼可以使用此方法來提供動(dòng)態(tài)創(chuàng)建的凍結(jié)模塊集合。
所以操縱這個(gè)指針甚至可以證明是有用的。為了限制示例大小,我們僅顯示如何使用以下方法讀取此表ctypes
:
- >>> from ctypes import *
- >>>
- >>> class struct_frozen(Structure):
- ... _fields_ = [("name", c_char_p),
- ... ("code", POINTER(c_ubyte)),
- ... ("size", c_int)]
- ...
- >>>
我們已經(jīng)定義了數(shù)據(jù)類型,因此我們可以獲得指向表的指針:struct _frozen
- >>> FrozenTable = POINTER(struct_frozen)
- >>> table = FrozenTable.in_dll(pythonapi, "PyImport_FrozenModules")
- >>>
因?yàn)?code>table是一個(gè)記錄pointer
數(shù)組struct_frozen
,我們可以迭代它,但我們必須確保我們的循環(huán)終止,因?yàn)橹羔槢]有大小。遲早它可能會(huì)因訪問沖突或其他原因而崩潰,所以當(dāng)我們點(diǎn)擊NULL條目時(shí)最好突破循環(huán):
- >>> for item in table:
- ... print item.name, item.size
- ... if item.name is None:
- ... break
- ...
- __hello__ 104
- __phello__ -104
- __phello__.spam 104
- None 0
- >>>
標(biāo)準(zhǔn)Python具有凍結(jié)模塊和凍結(jié)包(由負(fù)大小成員指示)的事實(shí)并不為人所知,它僅用于測試。例如嘗試一下。import __hello__
在某些邊緣情況下ctypes
,您可能會(huì)發(fā)現(xiàn)實(shí)際情況以外的其他情況。
請考慮以下示例:
- >>> from ctypes import *
- >>> class POINT(Structure):
- ... _fields_ = ("x", c_int), ("y", c_int)
- ...
- >>> class RECT(Structure):
- ... _fields_ = ("a", POINT), ("b", POINT)
- ...
- >>> p1 = POINT(1, 2)
- >>> p2 = POINT(3, 4)
- >>> rc = RECT(p1, p2)
- >>> print rc.a.x, rc.a.y, rc.b.x, rc.b.y
- 1 2 3 4
- >>> # now swap the two points
- >>> rc.a, rc.b = rc.b, rc.a
- >>> print rc.a.x, rc.a.y, rc.b.x, rc.b.y
- 3 4 3 4
- >>>
嗯。我們當(dāng)然希望打印最后一份聲明。發(fā)生了什么?以下是上述行的步驟:3 4 1 2
rc.a, rc.b = rc.b, rc.a
- >>> temp0, temp1 = rc.b, rc.a
- >>> rc.a = temp0
- >>> rc.b = temp1
- >>>
請注意,temp0
并且temp1
還在使用的內(nèi)部緩沖器的對象rc
上述對象。因此執(zhí)行將緩沖區(qū)內(nèi)容復(fù)制到緩沖區(qū)中。反過來,這改變了內(nèi)容。因此,最后一項(xiàng)任務(wù),沒有預(yù)期的效果。rc.a = temp0
temp0
rc
temp1
rc.b = temp1
請記住,從Structure,Unions和Arrays中檢索子對象不會(huì)復(fù)制子對象,而是檢索訪問根對象底層緩沖區(qū)的包裝器對象。
另一個(gè)可能與預(yù)期不同的例子是:
- >>> s = c_char_p()
- >>> s.value = "abc def ghi"
- >>> s.value
- 'abc def ghi'
- >>> s.value is s.value
- False
- >>>
為什么打印False
?ctypes實(shí)例是包含內(nèi)存塊的對象以及訪問內(nèi)存內(nèi)容的一些描述符。在內(nèi)存塊中存儲(chǔ)Python對象不會(huì)存儲(chǔ)對象本身,而是存儲(chǔ)對象contents
的對象。再次訪問內(nèi)容每次構(gòu)造一個(gè)新的Python對象!
ctypes
為可變大小的數(shù)組和結(jié)構(gòu)提供了一些支持。
該resize()
函數(shù)可用于調(diào)整現(xiàn)有ctypes對象的內(nèi)存緩沖區(qū)的大小。該函數(shù)將對象作為第一個(gè)參數(shù),并將請求的大?。ㄒ宰止?jié)為單位)作為第二個(gè)參數(shù)。內(nèi)存塊不能小于對象類型指定的自然內(nèi)存塊,ValueError
如果嘗試,則引發(fā)a :
- >>> short_array = (c_short * 4)()
- >>> print sizeof(short_array)
- 8
- >>> resize(short_array, 4)
- Traceback (most recent call last):
- ...
- ValueError: minimum size is 8
- >>> resize(short_array, 32)
- >>> sizeof(short_array)
- 32
- >>> sizeof(type(short_array))
- 8
- >>>
這很好很好,但是如何訪問此數(shù)組中包含的其他元素?由于類型仍然只知道4個(gè)元素,因此訪問其他元素時(shí)會(huì)出錯(cuò):
- >>> short_array[:]
- [0, 0, 0, 0]
- >>> short_array[7]
- Traceback (most recent call last):
- ...
- IndexError: invalid index
- >>>
使用可變大小數(shù)據(jù)類型的另一種方法ctypes
是使用Python的動(dòng)態(tài)特性,并且在已知所需大小之后(根據(jù)具體情況)重新定義數(shù)據(jù)類型。
使用編譯語言編程時(shí),在編譯/鏈接程序時(shí)以及程序運(yùn)行時(shí)都會(huì)訪問共享庫。
該find_library()
函數(shù)的目的是以類似于編譯器的方式定位庫(在具有多個(gè)版本的共享庫的平臺(tái)上應(yīng)該加載最新版本),而ctypes庫加載器就像程序運(yùn)行時(shí)一樣,并直接調(diào)用運(yùn)行時(shí)加載程序。
該ctypes.util
模塊提供了一個(gè)函數(shù),可以幫助確定要加載的庫。
ctypes.util.
find_library
(姓名)
嘗試查找?guī)觳⒎祷芈窂矫?nbsp;名字是不一樣的任何前綴庫名的lib,標(biāo)的相同.so
,.dylib
或版本號(hào)(這是用于POSIX鏈接器選項(xiàng)的形式-l
)。如果找不到庫,則返回None
。
確切的功能取決于系統(tǒng)。
在Linux上,find_library()
嘗試運(yùn)行外部程序(/sbin/ldconfig
,gcc
,和objdump
)找到庫文件。它返回庫文件的文件名。這里有些例子:
- >>> 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'
- >>>
在OS X上,find_library()
嘗試幾個(gè)預(yù)定義的命名方案和路徑來定位庫,如果成功則返回完整路徑名:
- >>> from ctypes.util import find_library
- >>> find_library("c")
- '/usr/lib/libc.dylib'
- >>> find_library("m")
- '/usr/lib/libm.dylib'
- >>> find_library("bz2")
- '/usr/lib/libbz2.dylib'
- >>> find_library("AGL")
- '/System/Library/Frameworks/AGL.framework/AGL'
- >>>
在Windows上,find_library()
沿系統(tǒng)搜索路徑進(jìn)行搜索,并返回完整路徑名,但由于沒有預(yù)定義的命名方案,因此調(diào)用find_library("c")
將失敗并返回None
。
如果包裝共享庫ctypes
,它可以更好地確定在開發(fā)時(shí)共享庫的名字,并硬編碼到封裝模塊,而不是使用find_library()
定位在運(yùn)行時(shí)庫。
有幾種方法可以將共享庫加載到Python進(jìn)程中。一種方法是實(shí)例化以下類之一:
class ctypes.
CDLL
(name,mode = DEFAULT_MODE,handle = None,use_errno = False,use_last_error = False )
此類的實(shí)例表示已加載的共享庫。這些庫中的函數(shù)使用標(biāo)準(zhǔn)C調(diào)用約定,并假定返回 int
。
class ctypes.
OleDLL
(name,mode = DEFAULT_MODE,handle = None,use_errno = False,use_last_error = False )
僅限Windows:此類的實(shí)例表示已加載的共享庫,這些庫中的函數(shù)使用stdcall
調(diào)用約定,并假定返回特定于Windows的HRESULT
代碼。 HRESULT
values包含指定函數(shù)調(diào)用是否失敗或成功的信息,以及其他錯(cuò)誤代碼。如果返回值表示失敗,WindowsError
則自動(dòng)引發(fā)a。
class ctypes.
WinDLL
(name,mode = DEFAULT_MODE,handle = None,use_errno = False,use_last_error = False )
僅限Windows:此類的實(shí)例表示已加載的共享庫,這些庫中的函數(shù)使用stdcall
調(diào)用約定,并且int
默認(rèn)情況下假定返回。
在Windows CE上,僅使用標(biāo)準(zhǔn)調(diào)用約定,以方便 WinDLL
并OleDLL
使用此平臺(tái)上的標(biāo)準(zhǔn)調(diào)用約定。
Python 全局解釋器鎖在調(diào)用這些庫導(dǎo)出的任何函數(shù)之前發(fā)布,之后重新獲取。
class ctypes.
PyDLL
(name,mode = DEFAULT_MODE,handle = None )
CDLL
除了在函數(shù)調(diào)用期間未釋放Python GIL之外,此類的實(shí)例的行為與實(shí)例類似,并且在函數(shù)執(zhí)行之后,將檢查Python錯(cuò)誤標(biāo)志。如果設(shè)置了錯(cuò)誤標(biāo)志,則會(huì)引發(fā)Python異常。
因此,這僅對直接調(diào)用Python C api函數(shù)有用。
所有這些類都可以通過使用至少一個(gè)參數(shù)(共享庫的路徑名)調(diào)用它們來實(shí)例化。如果已有已加載的共享庫的現(xiàn)有句柄,則可以將其作為handle
命名參數(shù)傳遞,否則使用基礎(chǔ)平臺(tái)dlopen
或LoadLibrary
函數(shù)將庫加載到進(jìn)程中,并獲取它的句柄。
該模式參數(shù)可用于指定庫的加載方式。有關(guān)詳細(xì)信息,請參閱dlopen(3)聯(lián)機(jī)幫助頁。在Windows上,模式被忽略。在posix系統(tǒng)上,始終添加RTLD_NOW,并且不可配置。
該use_errno參數(shù),當(dāng)設(shè)置為true,使一個(gè)ctypes機(jī)制,允許訪問該系統(tǒng)errno
以安全的方式錯(cuò)誤號(hào)。 ctypes
維護(hù)系統(tǒng)errno
變量的線程局部副本; 如果在函數(shù)調(diào)用與ctypes私有副本交換之前調(diào)用用函數(shù)調(diào)用創(chuàng)建的外部函數(shù),use_errno=True
則在 errno
函數(shù)調(diào)用之后立即發(fā)生相同的操作。
該函數(shù)ctypes.get_errno()
返回ctypes私有副本的值,該函數(shù)將ctypes私有副本ctypes.set_errno()
更改為新值并返回前一個(gè)值。
的use_last_error參數(shù),設(shè)置為true時(shí),使能由所述管理Windows錯(cuò)誤代碼相同的機(jī)制GetLastError()
和 SetLastError()
Windows API函數(shù); ctypes.get_last_error()
并 ctypes.set_last_error()
用于請求和更改Windows錯(cuò)誤代碼的ctypes私有副本。
新的2.6版:該use_last_error和use_errno可選參數(shù)添加。
ctypes.
RTLD_GLOBAL
用作模式參數(shù)的標(biāo)志。在此標(biāo)志不可用的平臺(tái)上,它被定義為整數(shù)零。
ctypes.
RTLD_LOCAL
用作模式參數(shù)的標(biāo)志。在沒有此功能的平臺(tái)上,它與RTLD_GLOBAL相同。
ctypes.
DEFAULT_MODE
用于加載共享庫的默認(rèn)模式。在OSX 10.3上,這是 RTLD_GLOBAL,否則它與RTLD_LOCAL相同。
這些類的實(shí)例沒有公共方法。共享庫導(dǎo)出的函數(shù)可以作為屬性或索引進(jìn)行訪問。請注意,通過屬性訪問函數(shù)會(huì)緩存結(jié)果,因此每次重復(fù)訪問它都會(huì)返回相同的對象。另一方面,通過索引訪問它每次都會(huì)返回一個(gè)新對象:
- >>> libc.time == libc.time
- True
- >>> libc['time'] == libc['time']
- False
可以使用以下公共屬性,它們的名稱以下劃線開頭,以便不與導(dǎo)出的函數(shù)名沖突:
PyDLL.
_handle
用于訪問庫的系統(tǒng)句柄。
PyDLL.
_name
在構(gòu)造函數(shù)中傳遞的庫的名稱。
還可以使用其中一個(gè)預(yù)制對象(LibraryLoader
通過調(diào)用 LoadLibrary()
方法)或通過將庫檢索為加載程序?qū)嵗膶傩詠砑虞d共享庫。
class ctypes.
LibraryLoader
(dlltype )
加載共享庫的類。 dlltype應(yīng)該是一個(gè) CDLL
,PyDLL
,WinDLL
或OleDLL
類型。
__getattr__()
具有特殊行為:它允許通過將其作為庫加載器實(shí)例的屬性訪問來加載共享庫。結(jié)果是緩存的,因此重復(fù)的屬性訪問每次都返回相同的庫。
LoadLibrary
(名字)
將共享庫加載到進(jìn)程中并返回它。此方法始終返回庫的新實(shí)例。
這些預(yù)制庫加載器可用:
ctypes.
cdll
創(chuàng)建CDLL
實(shí)例。
ctypes.
windll
僅限Windows:創(chuàng)建WinDLL
實(shí)例。
ctypes.
oledll
僅限Windows:創(chuàng)建OleDLL
實(shí)例。
ctypes.
pydll
創(chuàng)建PyDLL
實(shí)例。
為了直接訪問C Python api,可以使用現(xiàn)成的Python共享庫對象:
ctypes.
pythonapi
它的一個(gè)實(shí)例PyDLL
將Python C API函數(shù)公開為屬性。請注意,假設(shè)所有這些函數(shù)都返回C int
,這當(dāng)然不總是事實(shí),因此您必須分配正確的restype
屬性才能使用這些函數(shù)。
如前一節(jié)所述,外部函數(shù)可以作為加載的共享庫的屬性進(jìn)行訪問。默認(rèn)情況下以這種方式創(chuàng)建的函數(shù)對象接受任意數(shù)量的參數(shù),接受任何ctypes數(shù)據(jù)實(shí)例作為參數(shù),并返回庫加載器指定的默認(rèn)結(jié)果類型。他們是私人班級的實(shí)例:
類ctypes.
_FuncPtr
C可調(diào)用外部函數(shù)的基類。
外部函數(shù)的實(shí)例也是C兼容的數(shù)據(jù)類型; 它們代表C函數(shù)指針。
可以通過分配外部函數(shù)對象的特殊屬性來自定義此行為。
restype
指定ctypes類型以指定外部函數(shù)的結(jié)果類型。使用None
的void
,功能不返回任何東西。
可以分配不是ctypes類型的可調(diào)用Python對象,在這種情況下假定函數(shù)返回C int
,并且將使用此整數(shù)調(diào)用callable,從而允許進(jìn)一步處理或錯(cuò)誤檢查。不推薦使用它,為了更靈活的后處理或錯(cuò)誤檢查,請使用ctypes數(shù)據(jù)類型, restype
并為該errcheck
屬性分配一個(gè)callable 。
argtypes
分配ctypes類型的元組以指定函數(shù)接受的參數(shù)類型。使用stdcall
調(diào)用約定的函數(shù)只能使用與此元組的長度相同的參數(shù)數(shù)來調(diào)用; 使用C調(diào)用約定的函數(shù)也接受其他未指定的參數(shù)。
當(dāng)調(diào)用外部函數(shù)時(shí),每個(gè)實(shí)際參數(shù)都傳遞給 元組中from_param()
項(xiàng)的 類方法argtypes
,此方法允許將實(shí)際參數(shù)調(diào)整為外部函數(shù)接受的對象。例如,元組中的c_char_p
項(xiàng)argtypes
將使用ctypes轉(zhuǎn)換規(guī)則將作為參數(shù)傳遞的unicode字符串轉(zhuǎn)換為字節(jié)字符串。
新增:現(xiàn)在可以將項(xiàng)目放在不是ctypes類型的argtypes中,但每個(gè)項(xiàng)目必須有一個(gè)from_param()
返回可用作參數(shù)的值的方法(整數(shù),字符串,ctypes實(shí)例)。這允許定義可以將自定義對象調(diào)整為函數(shù)參數(shù)的適配器。
errcheck
為此屬性分配Python函數(shù)或其他可調(diào)用函數(shù)。將使用三個(gè)或更多參數(shù)調(diào)用callable:
callable
(結(jié)果,函數(shù),參數(shù))
result是外部函數(shù)返回的內(nèi)容,由restype
屬性指定 。
func是外部函數(shù)對象本身,這允許重用相同的可調(diào)用對象來檢查或后處理幾個(gè)函數(shù)的結(jié)果。
arguments是一個(gè)包含最初傳遞給函數(shù)調(diào)用的參數(shù)的元組,這允許對所使用的參數(shù)進(jìn)行特殊處理。
此函數(shù)返回的對象將從外部函數(shù)調(diào)用返回,但如果外部函數(shù)調(diào)用失敗,它還可以檢查結(jié)果值并引發(fā)異常。
異常ctypes.
ArgumentError
當(dāng)外部函數(shù)調(diào)用無法轉(zhuǎn)換其中一個(gè)傳遞的參數(shù)時(shí),會(huì)引發(fā)此異常。
也可以通過實(shí)例化函數(shù)原型來創(chuàng)建外部函數(shù)。函數(shù)原型類似于C中的函數(shù)原型; 它們描述了一個(gè)函數(shù)(返回類型,參數(shù)類型,調(diào)用約定)而沒有定義實(shí)現(xiàn)。必須使用所需的結(jié)果類型和函數(shù)的參數(shù)類型調(diào)用工廠函數(shù)。
ctypes.
CFUNCTYPE
(restype,* argtypes,use_errno = False,use_last_error = False )
返回的函數(shù)原型創(chuàng)建使用標(biāo)準(zhǔn)C調(diào)用約定的函數(shù)。該功能將在通話期間釋放GIL。如果 use_errno設(shè)置為true,則系統(tǒng)errno
變量的ctypes私有副本將 與errno
調(diào)用前后的實(shí)際值進(jìn)行交換; use_last_error對Windows錯(cuò)誤代碼執(zhí)行相同操作。
版本2.6中已更改:添加了可選的use_errno和use_last_error參數(shù)。
ctypes.
WINFUNCTYPE
(restype,* argtypes,use_errno = False,use_last_error = False )
僅適用于Windows:返回的函數(shù)原型創(chuàng)建使用函數(shù) stdcall
調(diào)用約定,除了Windows CE地方 WINFUNCTYPE()
是一樣的CFUNCTYPE()
。該功能將在通話期間釋放GIL。 use_errno和use_last_error具有與上面相同的含義。
ctypes.
PYFUNCTYPE
(restype,* argtypes )
返回的函數(shù)原型創(chuàng)建使用Python調(diào)用約定的函數(shù)。該功能在通話期間不會(huì)釋放GIL。
由這些工廠函數(shù)創(chuàng)建的函數(shù)原型可以以不同的方式實(shí)例化,具體取決于調(diào)用中參數(shù)的類型和數(shù)量:
prototype
(地址)返回指定地址的外部函數(shù),該函數(shù)必須是整數(shù)。
prototype
(可贖回)從Python 可調(diào)用創(chuàng)建C可調(diào)用函數(shù)(回調(diào)函數(shù))。
prototype
(func_spec [,paramflags ] )返回由共享庫導(dǎo)出的外部函數(shù)。func_spec必須是2元組。第一項(xiàng)是導(dǎo)出函數(shù)的名稱作為字符串,或?qū)С龊瘮?shù)的序號(hào)作為小整數(shù)。第二項(xiàng)是共享庫實(shí)例。
(name_or_ordinal, library)
prototype
(vtbl_index,name [,paramflags [,iid ] ] )返回將調(diào)用COM方法的外部函數(shù)。vtbl_index是虛函數(shù)表的索引,是一個(gè)小的非負(fù)整數(shù)。name是COM方法的名稱。iid是指向擴(kuò)展錯(cuò)誤報(bào)告中使用的接口標(biāo)識(shí)符的可選指針。
COM方法使用特殊的調(diào)用約定:除了
argtypes
元組中指定的那些參數(shù)外,它們還需要指向COM接口的指針作為第一個(gè)參數(shù)。可選的paramflags參數(shù)創(chuàng)建的外部函數(shù)包裝器具有比上述功能更多的功能。
paramflags必須是一個(gè)長度相同的元組
argtypes
。此元組中的每個(gè)項(xiàng)目都包含有關(guān)參數(shù)的更多信息,它必須是包含一個(gè),兩個(gè)或三個(gè)項(xiàng)目的元組。
第一項(xiàng)是一個(gè)整數(shù),包含參數(shù)的方向標(biāo)志組合:
1
指定函數(shù)的輸入?yún)?shù)。
2
輸出參數(shù)。外來函數(shù)填入一個(gè)值。
4
輸入?yún)?shù),默認(rèn)為整數(shù)零。
可選的第二項(xiàng)是參數(shù)名稱為字符串。如果指定了此參數(shù),則可以使用命名參數(shù)調(diào)用外部函數(shù)。
可選的第三項(xiàng)是此參數(shù)的默認(rèn)值。
此示例演示如何包裝Windows MessageBoxA
函數(shù),以便它支持默認(rèn)參數(shù)和命名參數(shù)。Windows頭文件中的C聲明是這樣的:
- WINUSERAPI int WINAPI
- MessageBoxA(
- HWND hWnd,
- LPCSTR lpText,
- LPCSTR lpCaption,
- UINT uType);
這是包裝ctypes
:
- >>> from ctypes import c_int, WINFUNCTYPE, windll
- >>> from ctypes.wintypes import HWND, LPCSTR, UINT
- >>> prototype = WINFUNCTYPE(c_int, HWND, LPCSTR, LPCSTR, UINT)
- >>> paramflags = (1, "hwnd", 0), (1, "text", "Hi"), (1, "caption", None), (1, "flags", 0)
- >>> MessageBox = prototype(("MessageBoxA", windll.user32), paramflags)
- >>>
現(xiàn)在可以通過以下方式調(diào)用MessageBox外部函數(shù):
- >>> MessageBox()
- >>> MessageBox(text="Spam, spam, spam")
- >>> MessageBox(flags=2, text="foo bar")
- >>>
第二個(gè)例子演示了輸出參數(shù)。win32 GetWindowRect
函數(shù)通過將指定窗口的尺寸復(fù)制到RECT
調(diào)用者必須提供的結(jié)構(gòu)中來檢索它們的尺寸 。這是C聲明:
- WINUSERAPI BOOL WINAPI
- GetWindowRect(
- HWND hWnd,
- LPRECT lpRect);
這是包裝ctypes
:
- >>> from ctypes import POINTER, WINFUNCTYPE, windll, WinError
- >>> from ctypes.wintypes import BOOL, HWND, RECT
- >>> prototype = WINFUNCTYPE(BOOL, HWND, POINTER(RECT))
- >>> paramflags = (1, "hwnd"), (2, "lprect")
- >>> GetWindowRect = prototype(("GetWindowRect", windll.user32), paramflags)
- >>>
具有輸出參數(shù)的函數(shù)將自動(dòng)返回輸出參數(shù)值(如果存在單個(gè)參數(shù)值)或者包含輸出參數(shù)值的元組(如果有多個(gè)),則GetWindowRect函數(shù)現(xiàn)在會(huì)在調(diào)用時(shí)返回RECT實(shí)例。
輸出參數(shù)可以與errcheck
協(xié)議組合以進(jìn)行進(jìn)一步的輸出處理和錯(cuò)誤檢查。win32 GetWindowRect
api函數(shù)返回一個(gè)BOOL
指示成功或失敗的信號(hào),因此該函數(shù)可以執(zhí)行錯(cuò)誤檢查,并在api調(diào)用失敗時(shí)引發(fā)異常:
- >>> def errcheck(result, func, args):
- ... if not result:
- ... raise WinError()
- ... return args
- ...
- >>> GetWindowRect.errcheck = errcheck
- >>>
如果errcheck
函數(shù)返回參數(shù)tuple,它接收不變,ctypes
繼續(xù)對輸出參數(shù)進(jìn)行的正常處理。如果要返回窗口坐標(biāo)而不是RECT
實(shí)例的元組 ,可以檢索函數(shù)中的字段并返回它們,將不再進(jìn)行正常處理:
- >>> def errcheck(result, func, args):
- ... if not result:
- ... raise WinError()
- ... rc = args[1]
- ... return rc.left, rc.top, rc.bottom, rc.right
- ...
- >>> GetWindowRect.errcheck = errcheck
- >>>
ctypes.
addressof
(obj )
以整數(shù)形式返回內(nèi)存緩沖區(qū)的地址。 obj必須是ctypes類型的實(shí)例。
ctypes.
alignment
(obj_or_type )
返回ctypes類型的對齊要求。obj_or_type必須是ctypes類型或?qū)嵗?/p>
ctypes.
byref
(obj [,offset ] )
返回一個(gè)指向obj的輕量級指針,該指針必須是ctypes類型的一個(gè)實(shí)例。 offset默認(rèn)為零,并且必須是將添加到內(nèi)部指針值的整數(shù)。
byref(obj, offset)
對應(yīng)于此C代碼:
(((char *)&obj) + offset)
返回的對象只能用作外部函數(shù)調(diào)用參數(shù)。它的行為類似pointer(obj)
,但構(gòu)造速度要快得多。
:在2.6版本中的新的偏移添加可選的參數(shù)。
ctypes.
cast
(obj,type )
此函數(shù)類似于C中的強(qiáng)制轉(zhuǎn)換運(yùn)算符。它返回一個(gè)新的類型實(shí)例,它指向與obj相同的內(nèi)存塊。 type 必須是指針類型,obj必須是可以解釋為指針的對象。
ctypes.
create_string_buffer
(init_or_size [,size ] )
此函數(shù)創(chuàng)建一個(gè)可變字符緩沖區(qū)。返回的對象是ctypes數(shù)組c_char
。
init_or_size必須是一個(gè)整數(shù),它指定數(shù)組的大小,或者是一個(gè)用于初始化數(shù)組項(xiàng)的字符串。
如果將字符串指定為第一個(gè)參數(shù),則將緩沖區(qū)設(shè)置為大于字符串長度的一個(gè)項(xiàng)目,以便數(shù)組中的最后一個(gè)元素是NUL終止字符??梢詫⒄麛?shù)作為第二個(gè)參數(shù)傳遞,如果不應(yīng)使用字符串的長度,則允許指定數(shù)組的大小。
如果第一個(gè)參數(shù)是unicode字符串,則根據(jù)ctypes轉(zhuǎn)換規(guī)則將其轉(zhuǎn)換為8位字符串。
ctypes.
create_unicode_buffer
(init_or_size [,size ] )
此函數(shù)創(chuàng)建一個(gè)可變的unicode字符緩沖區(qū)。返回的對象是ctypes數(shù)組c_wchar
。
init_or_size必須是指定數(shù)組大小的整數(shù),或者是用于初始化數(shù)組項(xiàng)的unicode字符串。
如果將unicode字符串指定為第一個(gè)參數(shù),則將緩沖區(qū)設(shè)置為大于字符串長度的一個(gè)項(xiàng)目,以便數(shù)組中的最后一個(gè)元素是NUL終止字符??梢詫⒄麛?shù)作為第二個(gè)參數(shù)傳遞,如果不應(yīng)使用字符串的長度,則允許指定數(shù)組的大小。
如果第一個(gè)參數(shù)是8位字符串,則根據(jù)ctypes轉(zhuǎn)換規(guī)則將其轉(zhuǎn)換為unicode字符串。
ctypes.
DllCanUnloadNow
()
僅限Windows:此函數(shù)是一個(gè)鉤子,允許使用ctypes實(shí)現(xiàn)進(jìn)程內(nèi)COM服務(wù)器。從DllCanUnloadNow函數(shù)調(diào)用_ctypes擴(kuò)展dll導(dǎo)出。
ctypes.
DllGetClassObject
()
僅限Windows:此函數(shù)是一個(gè)鉤子,允許使用ctypes實(shí)現(xiàn)進(jìn)程內(nèi)COM服務(wù)器。它是從_ctypes
擴(kuò)展dll導(dǎo)出的DllGetClassObject函數(shù)調(diào)用的。
ctypes.util.
find_library
(名字)
嘗試查找?guī)觳⒎祷芈窂矫?nbsp;name是沒有任何前綴的庫名,如lib
后綴.so
,.dylib
或版本號(hào)(這是用于posix鏈接器選項(xiàng)的形式-l
)。如果找不到庫,則返回None
。
確切的功能取決于系統(tǒng)。
在版本2.6中更改:僅限Windows:find_library("m")
或find_library("c")
將調(diào)用的結(jié)果返回到find_msvcrt()
。
ctypes.util.
find_msvcrt
()
僅限Windows:返回Python使用的VC運(yùn)行時(shí)庫的文件名,以及擴(kuò)展模塊。如果無法確定庫的名稱,None
則返回。
如果需要釋放內(nèi)存,例如,由擴(kuò)展模塊調(diào)用的內(nèi)存,則必須在分配內(nèi)存的同一庫中使用該功能。free(void *)
版本2.6中的新功能。
ctypes.
FormatError
([ code ] )
僅適用于Windows:返回的錯(cuò)誤代碼的文本描述代碼。如果未指定錯(cuò)誤代碼,則通過調(diào)用Windows api函數(shù)GetLastError來使用上一個(gè)錯(cuò)誤代碼。
ctypes.
GetLastError
()
僅限Windows:返回Windows在調(diào)用線程中設(shè)置的最后一個(gè)錯(cuò)誤代碼。此函數(shù)直接調(diào)用Windows GetLastError()函數(shù),它不返回錯(cuò)誤代碼的ctypes-private副本。
ctypes.
get_errno
()
返回errno
調(diào)用線程中系統(tǒng)變量的ctypes-private副本的當(dāng)前值 。
版本2.6中的新功能。
ctypes.
get_last_error
()
僅限Windows:返回LastError
調(diào)用線程中系統(tǒng)變量的ctypes-private副本的當(dāng)前值 。
版本2.6中的新功能。
ctypes.
memmove
(dst,src,count )
與標(biāo)準(zhǔn)C memmove庫函數(shù)相同:將計(jì)數(shù)字節(jié)從 src復(fù)制到dst。dst和src必須是可以轉(zhuǎn)換為指針的整數(shù)或ctypes實(shí)例。
ctypes.
memset
(dst,c,count )
與標(biāo)準(zhǔn)C memset庫函數(shù)相同:使用值c的計(jì)數(shù)字節(jié)填充地址dst處的內(nèi)存塊。dst必須是指定地址的整數(shù)或ctypes實(shí)例。
ctypes.
POINTER
(類型)
此工廠函數(shù)創(chuàng)建并返回新的ctypes指針類型。指針類型在內(nèi)部被緩存和重用,因此重復(fù)調(diào)用此函數(shù)很便宜。type必須是ctypes類型。
ctypes.
pointer
(obj )
此函數(shù)創(chuàng)建一個(gè)指向obj的新指針實(shí)例。返回的對象屬于該類型POINTER(type(obj))
。
注意:如果您只想將指向?qū)ο蟮闹羔槀鬟f給外部函數(shù)調(diào)用,則應(yīng)該使用byref(obj)
哪個(gè)更快。
ctypes.
resize
(obj,size )
此函數(shù)調(diào)整obj的內(nèi)部內(nèi)存緩沖區(qū)的大小,obj必須是ctypes類型的實(shí)例。如下所示,不可能使緩沖區(qū)小于對象類型的本機(jī)大小sizeof(type(obj))
,但可以放大緩沖區(qū)。
ctypes.
set_conversion_mode
(編碼,錯(cuò)誤)
此函數(shù)設(shè)置ctypes對象在8位字符串和unicode字符串之間進(jìn)行轉(zhuǎn)換時(shí)使用的規(guī)則。 encoding必須是指定編碼的字符串,如'utf-8'
或'mbcs'
,錯(cuò)誤必須是一個(gè)字符串,指定編碼/解碼錯(cuò)誤的錯(cuò)誤處理??赡艿闹档膶?shí)例是"strict"
,"replace"
,或"ignore"
。
set_conversion_mode()
返回包含先前轉(zhuǎn)換規(guī)則的2元組。在Windows上,初始轉(zhuǎn)換規(guī)則在其他系統(tǒng)上。('mbcs', 'ignore')
('ascii', 'strict')
ctypes.
set_errno
(值)
將errno
調(diào)用線程中系統(tǒng)變量的ctypes-private副本的當(dāng)前值設(shè)置為value并返回先前的值。
版本2.6中的新功能。
ctypes.
set_last_error
(值)
僅限Windows:將LastError
調(diào)用線程中系統(tǒng)變量的ctypes-private副本的當(dāng)前值設(shè)置 為value并返回先前的值。
版本2.6中的新功能。
ctypes.
sizeof
(obj_or_type )
返回ctypes類型或?qū)嵗齼?nèi)存緩沖區(qū)的大?。ㄒ宰止?jié)為單位)。與C sizeof
運(yùn)算符相同。
ctypes.
string_at
(地址[,大小] )
這個(gè)函數(shù)返回了從內(nèi)存地址字符串地址。如果指定了size,則將其用作size,否則假定該字符串為零終止。
ctypes.
WinError
(code = None,descr = None )
僅限Windows:此函數(shù)可能是ctypes中最糟糕的名稱。它創(chuàng)建了一個(gè)WindowsError實(shí)例。如果未指定代碼, GetLastError
則調(diào)用以確定錯(cuò)誤代碼。如果descr
未指定,FormatError()
則調(diào)用以獲取錯(cuò)誤的文本描述。
ctypes.
wstring_at
(地址[,大小] )
這個(gè)函數(shù)返回了從內(nèi)存地址寬字符串 地址為unicode字符串。如果指定了size,則將其用作字符串的字符數(shù),否則假定該字符串為零終止。
類ctypes.
_CData
這個(gè)非公共類是所有ctypes數(shù)據(jù)類型的公共基類。除此之外,所有ctypes類型實(shí)例都包含一個(gè)保存C兼容數(shù)據(jù)的內(nèi)存塊; addressof()
輔助函數(shù)返回內(nèi)存塊的地址 。另一個(gè)實(shí)例變量暴露為 _objects
; 這包含其他需要保持活動(dòng)的Python對象,以防內(nèi)存塊包含指針。
ctypes數(shù)據(jù)類型的常用方法,這些都是類方法(確切地說,它們是元類的方法):
from_buffer
(來源[,偏移] )
此方法返回共享源對象的緩沖區(qū)的ctypes實(shí)例 。所述源對象必須支持可寫緩沖器接口??蛇x的offset參數(shù)指定源緩沖區(qū)的偏移量(以字節(jié)為單位); 默認(rèn)值為零。如果源緩沖區(qū)不夠大,ValueError
則會(huì)引發(fā)a。
版本2.6中的新功能。
from_buffer_copy
(來源[,偏移] )
此方法創(chuàng)建一個(gè)ctypes實(shí)例,從源對象緩沖區(qū)復(fù)制緩沖區(qū),該 緩沖區(qū)必須是可讀的。可選的offset 參數(shù)指定源緩沖區(qū)的偏移量(以字節(jié)為單位); 默認(rèn)值為零。如果源緩沖區(qū)不夠大,ValueError
則會(huì)引發(fā)a。
版本2.6中的新功能。
from_address
(地址)
此方法使用address指定的內(nèi)存返回ctypes類型實(shí)例,該內(nèi)存 必須是整數(shù)。
from_param
(obj )
此方法使obj適應(yīng)ctypes類型。當(dāng)外部函數(shù)的argtypes
元組中存在類型時(shí),使用外部函數(shù)調(diào)用中使用的實(shí)際對象調(diào)用它; 它必須返回一個(gè)可以用作函數(shù)調(diào)用參數(shù)的對象。
所有ctypes數(shù)據(jù)類型都具有此類方法的默認(rèn)實(shí)現(xiàn),如果是類型的實(shí)例,則通常返回obj。某些類型也接受其他對象。
in_dll
(圖書館,名稱)
此方法返回由共享庫導(dǎo)出的ctypes類型實(shí)例。name是導(dǎo)出數(shù)據(jù)的符號(hào)的名稱,library 是加載的共享庫。
ctypes數(shù)據(jù)類型的常見實(shí)例變量:
_b_base_
有時(shí)ctypes數(shù)據(jù)實(shí)例不擁有它們包含的內(nèi)存塊,而是共享基礎(chǔ)對象的部分內(nèi)存塊。所述 _b_base_
只讀構(gòu)件是根ctypes的對象擁有該存儲(chǔ)器塊。
_b_needsfree_
當(dāng)ctypes數(shù)據(jù)實(shí)例已分配內(nèi)存塊本身時(shí),此只讀變量為true,否則為false。
_objects
該成員None
或者是包含需要保持活動(dòng)的Python對象的字典,以便內(nèi)存塊內(nèi)容保持有效。該對象僅用于調(diào)試; 永遠(yuǎn)不要修改這本詞典的內(nèi)容。
類ctypes.
_SimpleCData
這個(gè)非公共類是所有基本ctypes數(shù)據(jù)類型的基類。這里提到它是因?yàn)樗綾types數(shù)據(jù)類型的公共屬性。 _SimpleCData
是它的子類 _CData
,因此它繼承了它們的方法和屬性。
在版本2.6中更改:現(xiàn)在可以對不包含指針但不包含指針的ctypes數(shù)據(jù)類型進(jìn)行pickle。
實(shí)例具有單個(gè)屬性:
value
該屬性包含實(shí)例的實(shí)際值。對于整數(shù)和指針類型,它是一個(gè)整數(shù),對于字符類型,它是單個(gè)字符串,對于字符指針類型,它是Python字符串或unicode字符串。
當(dāng)value
屬性從一個(gè)ctypes實(shí)例獲取,通常是一個(gè)新的對象,每次返回。 ctypes
并沒有實(shí)現(xiàn)原來的目標(biāo)回報(bào)率,總是一個(gè)新的對象被創(chuàng)建。所有其他ctypes對象實(shí)例也是如此。
基本數(shù)據(jù)類型作為外部函數(shù)調(diào)用結(jié)果返回時(shí),或者例如通過檢索結(jié)構(gòu)字段成員或數(shù)組項(xiàng),將透明地轉(zhuǎn)換為本機(jī)Python類型。換句話說,如果一個(gè)外國函數(shù)有一個(gè) restype
的c_char_p
,你總是會(huì)收到一個(gè)Python字符串, 不是一個(gè)c_char_p
實(shí)例。
基本數(shù)據(jù)類型的子類不會(huì)繼承此行為。因此,如果外部函數(shù)restype
是其子類c_void_p
,您將從函數(shù)調(diào)用中接收此子類的實(shí)例。當(dāng)然,您可以通過訪問value
屬性來獲取指針的值。
這些是基本的ctypes數(shù)據(jù)類型:
類ctypes.
c_byte
表示C 數(shù)據(jù)類型,并將該值解釋為小整數(shù)。構(gòu)造函數(shù)接受可選的整數(shù)初始值設(shè)定項(xiàng); 沒有進(jìn)行溢出檢查。signed char
類ctypes.
c_char
表示C char
數(shù)據(jù)類型,并將該值解釋為單個(gè)字符。構(gòu)造函數(shù)接受可選的字符串初始值設(shè)定項(xiàng),字符串的長度必須恰好是一個(gè)字符。
類ctypes.
c_char_p
當(dāng)它指向以零結(jié)尾的字符串時(shí)表示C 數(shù)據(jù)類型。對于也可能指向二進(jìn)制數(shù)據(jù)的通用字符指針, 必須使用。構(gòu)造函數(shù)接受整數(shù)地址或字符串。char *
POINTER(c_char)
類ctypes.
c_double
表示C double
數(shù)據(jù)類型。構(gòu)造函數(shù)接受可選的float初始化程序。
類ctypes.
c_longdouble
表示C 數(shù)據(jù)類型。構(gòu)造函數(shù)接受可選的float初始化程序。在它是別名的平臺(tái)上。long double
sizeof(long double) == sizeof(double)
c_double
版本2.6中的新功能。
類ctypes.
c_float
表示C float
數(shù)據(jù)類型。構(gòu)造函數(shù)接受可選的float初始化程序。
類ctypes.
c_int
表示C 數(shù)據(jù)類型。構(gòu)造函數(shù)接受可選的整數(shù)初始值設(shè)定項(xiàng); 沒有進(jìn)行溢出檢查。在它是別名的平臺(tái)上。signed int
sizeof(int) == sizeof(long)
c_long
類ctypes.
c_int8
表示C 8位數(shù)據(jù)類型。通常是別名 。signed int
c_byte
類ctypes.
c_int16
表示C 16位數(shù)據(jù)類型。通常是別名 。signed int
c_short
類ctypes.
c_int32
表示C 32位數(shù)據(jù)類型。通常是別名 。signed int
c_int
類ctypes.
c_int64
表示C 64位數(shù)據(jù)類型。通常是別名 。signed int
c_longlong
類ctypes.
c_long
表示C 數(shù)據(jù)類型。構(gòu)造函數(shù)接受可選的整數(shù)初始值設(shè)定項(xiàng); 沒有進(jìn)行溢出檢查。signed long
類ctypes.
c_longlong
表示C 數(shù)據(jù)類型。構(gòu)造函數(shù)接受可選的整數(shù)初始值設(shè)定項(xiàng); 沒有進(jìn)行溢出檢查。signed long long
類ctypes.
c_short
表示C 數(shù)據(jù)類型。構(gòu)造函數(shù)接受可選的整數(shù)初始值設(shè)定項(xiàng); 沒有進(jìn)行溢出檢查。signed short
類ctypes.
c_size_t
表示C size_t
數(shù)據(jù)類型。
類ctypes.
c_ssize_t
表示C ssize_t
數(shù)據(jù)類型。
版本2.7中的新功能。
類ctypes.
c_ubyte
表示C 數(shù)據(jù)類型,它將值解釋為小整數(shù)。構(gòu)造函數(shù)接受可選的整數(shù)初始值設(shè)定項(xiàng); 沒有進(jìn)行溢出檢查。unsigned char
類ctypes.
c_uint
表示C 數(shù)據(jù)類型。構(gòu)造函數(shù)接受可選的整數(shù)初始值設(shè)定項(xiàng); 沒有進(jìn)行溢出檢查。在它是別名的平臺(tái)上。unsigned int
sizeof(int) == sizeof(long)
c_ulong
類ctypes.
c_uint8
表示C 8位數(shù)據(jù)類型。通常是別名 。unsigned int
c_ubyte
類ctypes.
c_uint16
表示C 16位數(shù)據(jù)類型。通常是別名 。unsigned int
c_ushort
類ctypes.
c_uint32
表示C 32位數(shù)據(jù)類型。通常是別名 。unsigned int
c_uint
類ctypes.
c_uint64
表示C 64位數(shù)據(jù)類型。通常是別名 。unsigned int
c_ulonglong
類ctypes.
c_ulong
表示C 數(shù)據(jù)類型。構(gòu)造函數(shù)接受可選的整數(shù)初始值設(shè)定項(xiàng); 沒有進(jìn)行溢出檢查。unsigned long
類ctypes.
c_ulonglong
表示C 數(shù)據(jù)類型。構(gòu)造函數(shù)接受可選的整數(shù)初始值設(shè)定項(xiàng); 沒有進(jìn)行溢出檢查。unsigned long long
類ctypes.
c_ushort
表示C 數(shù)據(jù)類型。構(gòu)造函數(shù)接受可選的整數(shù)初始值設(shè)定項(xiàng); 沒有進(jìn)行溢出檢查。unsigned short
類ctypes.
c_void_p
表示C 類型。該值表示為整數(shù)。構(gòu)造函數(shù)接受可選的整數(shù)初始值設(shè)定項(xiàng)。void *
類ctypes.
c_wchar
表示C wchar_t
數(shù)據(jù)類型,并將該值解釋為單個(gè)字符的unicode字符串。構(gòu)造函數(shù)接受可選的字符串初始值設(shè)定項(xiàng),字符串的長度必須恰好是一個(gè)字符。
類ctypes.
c_wchar_p
表示C 數(shù)據(jù)類型,該數(shù)據(jù)類型必須是指向以零結(jié)尾的寬字符串的指針。構(gòu)造函數(shù)接受整數(shù)地址或字符串。wchar_t *
類ctypes.
c_bool
表示C bool
數(shù)據(jù)類型(更準(zhǔn)確地說,_Bool
來自C99)。它的值可以是True
或者False
,構(gòu)造函數(shù)接受任何具有真值的對象。
版本2.6中的新功能。
類ctypes.
HRESULT
僅限Windows:表示一個(gè)HRESULT
值,其中包含函數(shù)或方法調(diào)用的成功或錯(cuò)誤信息。
類ctypes.
py_object
表示C 數(shù)據(jù)類型。在沒有參數(shù)的情況下調(diào)用它會(huì)創(chuàng)建一個(gè)指針。PyObject *
NULL
PyObject *
該ctypes.wintypes
模塊提供了相當(dāng)長的一段其他Windows特定的數(shù)據(jù)類型,例如HWND
,WPARAM
或DWORD
。一些有用的結(jié)構(gòu),如MSG
或RECT
定義。
class ctypes.
Union
(* args,** kw )
原始字節(jié)順序的聯(lián)合的抽象基類。
class ctypes.
BigEndianStructure
(* args,** kw )
大端字節(jié)順序結(jié)構(gòu)的抽象基類。
class ctypes.
LittleEndianStructure
(* args,** kw )
小端字節(jié)順序結(jié)構(gòu)的抽象基類。
具有非本機(jī)字節(jié)順序的結(jié)構(gòu)不能包含指針類型字段或包含指針類型字段的任何其他數(shù)據(jù)類型。
class ctypes.Structure(* args,** kw )
本機(jī)字節(jié)順序的結(jié)構(gòu)的抽象基類。
必須通過繼承其中一種類型來創(chuàng)建具體結(jié)構(gòu)和聯(lián)合類型,并至少定義一個(gè)_fields_
類變量。ctypes
將創(chuàng)建描述符 s,允許通過直接屬性訪問來讀取和寫入字段。這些是
_fields_
定義結(jié)構(gòu)字段的序列。項(xiàng)目必須是2元組或3元組。第一項(xiàng)是字段的名稱,第二項(xiàng)指定字段的類型; 它可以是任何ctypes數(shù)據(jù)類型。
對于整數(shù)類型字段c_int
,可以給出第三個(gè)可選項(xiàng)。它必須是一個(gè)小的正整數(shù),用于定義字段的位寬。
字段名稱在一個(gè)結(jié)構(gòu)或聯(lián)合中必須是唯一的。未選中此選項(xiàng),重復(fù)名稱時(shí)只能訪問一個(gè)字段。
可以在定義Structure子類的類語句之后定義_fields_
類變量,這允許創(chuàng)建直接或間接引用自身的數(shù)據(jù)類型:
- class List(Structure):
- pass
- List._fields_ = [("pnext", POINTER(List)),
- ...
- ]
的_fields_
類變量但是,必須被定義在第一次使用之前的類型(創(chuàng)建一個(gè)實(shí)例,sizeof()
被稱為其上,等等)。稍后對_fields_
類變量的賦值將引發(fā)AttributeError。
可以定義結(jié)構(gòu)類型的子類,它們繼承基類的字段以及_fields_
子子類中定義的字段(如果有的話)。
_pack_
一個(gè)可選的小整數(shù),允許覆蓋實(shí)例中結(jié)構(gòu)字段的對齊方式。 _pack_
必須在_fields_
分配時(shí)定義,否則它將無效。
_anonymous_
一個(gè)可選序列,列出未命名(匿名)字段的名稱。 _anonymous_
必須在_fields_
分配時(shí)定義,否則它將無效。
此變量中列出的字段必須是結(jié)構(gòu)或聯(lián)合類型字段。 ctypes
將在結(jié)構(gòu)類型中創(chuàng)建允許直接訪問嵌套字段的描述符,而無需創(chuàng)建結(jié)構(gòu)或聯(lián)合字段。
這是一個(gè)示例類型(Windows):
- class _U(Union):
- _fields_ = [("lptdesc", POINTER(TYPEDESC)),
- ("lpadesc", POINTER(ARRAYDESC)),
- ("hreftype", HREFTYPE)]
- class TYPEDESC(Structure):
- _anonymous_ = ("u",)
- _fields_ = [("u", _U),
- ("vt", VARTYPE)]
該TYPEDESC
結(jié)構(gòu)描述了COM數(shù)據(jù)類型,該vt
字段指定哪個(gè)聯(lián)合字段有效。由于該u
字段被定義為匿名字段,因此現(xiàn)在可以直接從TYPEDESC實(shí)例訪問成員。td.lptdesc
并且td.u.lptdesc
是等價(jià)的,但前者更快,因?yàn)樗恍枰獎(jiǎng)?chuàng)建臨時(shí)聯(lián)合實(shí)例:
- td = TYPEDESC()
- td.vt = VT_PTR
- td.lptdesc = POINTER(some_type)
- td.u.lptdesc = POINTER(some_type)
可以定義結(jié)構(gòu)的子類,它們繼承基類的字段。如果子類定義具有單獨(dú)的 _fields_
變量,則在此指定的字段將附加到基類的字段中。
結(jié)構(gòu)和聯(lián)合構(gòu)造函數(shù)接受位置和關(guān)鍵字參數(shù)。位置參數(shù)用于按照出現(xiàn)的順序初始化成員字段_fields_
。構(gòu)造函數(shù)中的關(guān)鍵字參數(shù)被解釋為屬性賦值,因此它們將_fields_
使用相同的名稱進(jìn)行初始化 ,或者為不存在的名稱創(chuàng)建新屬性_fields_
。
class ctypes.
Array
(* args )
數(shù)組的抽象基類。
創(chuàng)建具體數(shù)組類型的推薦方法是將任何ctypes
數(shù)據(jù)類型與正整數(shù)相乘 。或者,您可以繼承此類型并定義_length_
和_type_
類變量。可以使用標(biāo)準(zhǔn)下標(biāo)和切片訪問來讀取和寫入數(shù)組元素; 對于切片讀取,所得到的物體是 不本身Array
。
_length_
一個(gè)正整數(shù),指定數(shù)組中元素的數(shù)量。超出范圍的下標(biāo)導(dǎo)致IndexError
。將由返回len()
。
_type_
指定數(shù)組中每個(gè)元素的類型。
數(shù)組子類構(gòu)造函數(shù)接受位置參數(shù),用于按順序初始化元素。
類ctypes.
_Pointer
指針的私有抽象基類。
通過POINTER()
使用將指向的類型調(diào)用來創(chuàng)建具體指針類型; 這是由自動(dòng)完成的 pointer()
。
如果指針指向數(shù)組,則可以使用標(biāo)準(zhǔn)下標(biāo)和切片訪問來讀取和寫入其元素。指針對象沒有大小,因此len()
會(huì)提高TypeError
。否定下標(biāo)將在指針之前從內(nèi)存中讀?。ㄈ缭贑中),并且超出范圍的下標(biāo)可能會(huì)因訪問沖突而崩潰(如果您很幸運(yùn))。
_type_
指定指向的類型。
contents
返回指針指向的對象。分配給此屬性會(huì)將指針更改為指向指定的對象。
|