久久精品精选,精品九九视频,www久久只有这里有精品,亚洲熟女乱色综合一区
    分享

    python ctypes中文幫助文檔

     dinghj 2019-04-17

       15.17。ctypes- 用于Python的外部函數(shù)庫(kù)

    2.5版中的新功能。

    ctypes是Python的外部函數(shù)庫(kù)。它提供C兼容的數(shù)據(jù)類(lèi)型,并允許在DLL或共享庫(kù)中調(diào)用函數(shù)。它可以用于在純Python中包裝這些庫(kù)。

    15.17.1。ctypes教程

    注意:本教程中的代碼示例doctest用于確保它們實(shí)際工作。由于某些代碼示例在Linux,Windows或Mac OS X下的行為不同,因此它們?cè)谧⑨屩邪琩octest指令。

    注意:某些代碼示例引用了ctypes c_int類(lèi)型。此類(lèi)型是c_long32位系統(tǒng)上類(lèi)型的別名。因此,c_long如果您打算如果打印,則不應(yīng)該感到困惑c_int- 它們實(shí)際上是相同的類(lèi)型。

       15.17.1.1。加載動(dòng)態(tài)鏈接庫(kù)

    ctypes導(dǎo)出cdll,以及Windows windlloledll 對(duì)象,用于加載動(dòng)態(tài)鏈接庫(kù)。

    您可以通過(guò)訪(fǎng)問(wèn)它們作為這些對(duì)象的屬性來(lái)加載庫(kù)。cdll 加載使用標(biāo)準(zhǔn)cdecl調(diào)用約定導(dǎo)出函數(shù)的庫(kù),而windll庫(kù)使用stdcall 調(diào)用約定調(diào)用函數(shù)。oledll還使用stdcall調(diào)用約定,并假定函數(shù)返回Windows HRESULT錯(cuò)誤代碼。錯(cuò)誤代碼用于WindowsError在函數(shù)調(diào)用失敗時(shí)自動(dòng)引發(fā)異常。

    以下是Windows的一些示例。注意,它msvcrt是包含大多數(shù)標(biāo)準(zhǔn)C函數(shù)的MS標(biāo)準(zhǔn)C庫(kù),并使用cdecl調(diào)用約定:

    1. >>> from ctypes import *
    2. >>> print windll.kernel32
    3. <WinDLL 'kernel32', handle ... at ...>
    4. >>> print cdll.msvcrt
    5. <CDLL 'msvcrt', handle ... at ...>
    6. >>> libc = cdll.msvcrt
    7. >>>

    Windows會(huì).dll自動(dòng)附加常用的文件后綴。

    在Linux上,需要指定包含加載庫(kù)的擴(kuò)展名的文件名,因此不能使用屬性訪(fǎng)問(wèn)來(lái)加載庫(kù)。LoadLibrary()應(yīng)該使用dll加載器的 方法,或者你應(yīng)該通過(guò)調(diào)用構(gòu)造函數(shù)創(chuàng)建一個(gè)CDLL實(shí)例來(lái)加載庫(kù):

    1. >>> cdll.LoadLibrary("libc.so.6")
    2. <CDLL 'libc.so.6', handle ... at ...>
    3. >>> libc = CDLL("libc.so.6")
    4. >>> libc
    5. <CDLL 'libc.so.6', handle ... at ...>
    6. >>>

       15.17.1.2。從加載的dll訪(fǎng)問(wèn)函數(shù)

    函數(shù)作為dll對(duì)象的屬性進(jìn)行訪(fǎng)問(wèn):

    1. >>> from ctypes import *
    2. >>> libc.printf
    3. <_FuncPtr object at 0x...>
    4. >>> print windll.kernel32.GetModuleHandleA
    5. <_FuncPtr object at 0x...>
    6. >>> print windll.kernel32.MyOwnFunction
    7. Traceback (most recent call last):
    8. File "<stdin>", line 1, in <module>
    9. File "ctypes.py", line 239, in __getattr__
    10. func = _StdcallFuncPtr(name, self)
    11. AttributeError: function 'MyOwnFunction' not found
    12. >>>

    請(qǐng)注意,win32系統(tǒng)類(lèi)似于kernel32并且user32經(jīng)常導(dǎo)出ANSI以及函數(shù)的UNICODE版本。UNICODE版本將導(dǎo)出W并附加到名稱(chēng),而ANSI版本將導(dǎo)出A 并附加到名稱(chēng)。win32 GetModuleHandle函數(shù)返回給定模塊名稱(chēng)的 模塊句柄,具有以下C原型,并且GetModuleHandle根據(jù)是否定義了UNICODE ,使用宏來(lái)公開(kāi)其中一個(gè):

    1. /* ANSI version */
    2. HMODULE GetModuleHandleA(LPCSTR lpModuleName);
    3. /* UNICODE version */
    4. HMODULE GetModuleHandleW(LPCWSTR lpModuleName);

    windll不會(huì)嘗試通過(guò)魔法選擇其中一個(gè),您必須通過(guò)指定GetModuleHandleAGetModuleHandleW 顯式訪(fǎng)問(wèn)所需的版本,然后分別使用字符串或unicode字符串調(diào)用它。

    有時(shí),dll導(dǎo)出的函數(shù)名稱(chēng)不是有效的Python標(biāo)識(shí)符,例如"??2@YAPAXI@Z"。在這種情況下,您必須使用 getattr()檢索功能:

    1. >>> getattr(cdll.msvcrt, "??2@YAPAXI@Z")
    2. <_FuncPtr object at 0x...>
    3. >>>

    在Windows上,某些dll不按名稱(chēng)導(dǎo)出函數(shù),而是按順序?qū)С龊瘮?shù)。可以通過(guò)使用序號(hào)索引dll對(duì)象來(lái)訪(fǎng)問(wèn)這些函數(shù):

    1. >>> cdll.kernel32[1]
    2. <_FuncPtr object at 0x...>
    3. >>> cdll.kernel32[0]
    4. Traceback (most recent call last):
    5. File "<stdin>", line 1, in <module>
    6. File "ctypes.py", line 310, in __getitem__
    7. func = _StdcallFuncPtr(name, self)
    8. AttributeError: function ordinal 0 not found
    9. >>>

        15.17.1.3。調(diào)用函數(shù)

    您可以像調(diào)用任何其他Python一樣調(diào)用這些函數(shù)。此示例使用time()函數(shù),該函數(shù)返回自Unix紀(jì)元以來(lái)以秒為單位的系統(tǒng)時(shí)間,以及GetModuleHandleA()返回win32模塊句柄的函數(shù)。

    此示例使用NULL指針調(diào)用這兩個(gè)函數(shù)(None應(yīng)該用作NULL指針):

    1. >>> print libc.time(None)
    2. 1150640792
    3. >>> print hex(windll.kernel32.GetModuleHandleA(None))
    4. 0x1d000000
    5. >>>

    ctypes試圖保護(hù)您不要使用錯(cuò)誤的參數(shù)數(shù)量或錯(cuò)誤的調(diào)用約定來(lái)調(diào)用函數(shù)。不幸的是,這僅適用于Windows。它通過(guò)在函數(shù)返回后檢查堆棧來(lái)完成此操作,因此雖然引發(fā)了錯(cuò)誤,但函數(shù)被調(diào)用:

    1. >>> windll.kernel32.GetModuleHandleA()
    2. Traceback (most recent call last):
    3. File "<stdin>", line 1, in <module>
    4. ValueError: Procedure probably called with not enough arguments (4 bytes missing)
    5. >>> windll.kernel32.GetModuleHandleA(0, 0)
    6. Traceback (most recent call last):
    7. File "<stdin>", line 1, in <module>
    8. ValueError: Procedure probably called with too many arguments (4 bytes in excess)
    9. >>>

    stdcall使用cdecl調(diào)用約定調(diào)用函數(shù) 時(shí)會(huì)引發(fā)相同的異常,反之亦然:

    1. >>> cdll.kernel32.GetModuleHandleA(None)
    2. Traceback (most recent call last):
    3. File "<stdin>", line 1, in <module>
    4. ValueError: Procedure probably called with not enough arguments (4 bytes missing)
    5. >>>
    6. >>> windll.msvcrt.printf("spam")
    7. Traceback (most recent call last):
    8. File "<stdin>", line 1, in <module>
    9. ValueError: Procedure probably called with too many arguments (4 bytes in excess)
    10. >>>

    要找出正確的調(diào)用約定,您必須查看C頭文件或要調(diào)用的函數(shù)的文檔。

    在Windows上,ctypes使用win32結(jié)構(gòu)化異常處理來(lái)防止在使用無(wú)效參數(shù)值調(diào)用函數(shù)時(shí)因常規(guī)保護(hù)錯(cuò)誤而崩潰:

    1. >>> windll.kernel32.GetModuleHandleA(32)
    2. Traceback (most recent call last):
    3. File "<stdin>", line 1, in <module>
    4. WindowsError: exception: access violation reading 0x00000020
    5. >>>

    但是,有足夠的方法可以使Python崩潰ctypes,所以無(wú)論如何你應(yīng)該小心。

    None,整數(shù),長(zhǎng)整數(shù),字節(jié)字符串和unicode字符串是唯一可以直接用作這些函數(shù)調(diào)用中的參數(shù)的本機(jī)Python對(duì)象。 None作為C NULL指針傳遞,字節(jié)字符串和unicode字符串作為指針傳遞給包含其數(shù)據(jù)( 或)的內(nèi)存塊。Python整數(shù)和Python long作為平臺(tái)默認(rèn)C 類(lèi)型傳遞,它們的值被屏蔽以適合C類(lèi)型。char *wchar_t *int

    在我們繼續(xù)使用其他參數(shù)類(lèi)型調(diào)用函數(shù)之前,我們必須了解有關(guān)ctypes數(shù)據(jù)類(lèi)型的更多信息。

       15.17.1.4。基本數(shù)據(jù)類(lèi)型

    ctypes 定義了許多原始C兼容的數(shù)據(jù)類(lèi)型:

    ctypes類(lèi)型 C型 Python類(lèi)型
    c_bool _Bool 布爾(1)
    c_char char 1個(gè)字符的字符串
    c_wchar wchar_t 1個(gè)字符的unicode字符串
    c_byte char INT /長(zhǎng)
    c_ubyte unsigned char INT /長(zhǎng)
    c_short short INT /長(zhǎng)
    c_ushort unsigned short INT /長(zhǎng)
    c_int int INT /長(zhǎng)
    c_uint unsigned int INT /長(zhǎng)
    c_long long INT /長(zhǎng)
    c_ulong unsigned long INT /長(zhǎng)
    c_longlong __int64 要么 long long INT /長(zhǎng)
    c_ulonglong unsigned __int64 要么 unsigned long long INT /長(zhǎng)
    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
    1. 構(gòu)造函數(shù)接受具有真值的任何對(duì)象。

    所有這些類(lèi)型都可以通過(guò)使用正確類(lèi)型和值的可選初始化程序調(diào)用它們來(lái)創(chuàng)建:

    1. >>> c_int()
    2. c_long(0)
    3. >>> c_char_p("Hello, World")
    4. c_char_p('Hello, World')
    5. >>> c_ushort(-3)
    6. c_ushort(65533)
    7. >>>

    由于這些類(lèi)型是可變的,因此它們的值也可以在以后更改:

    1. >>> i = c_int(42)
    2. >>> print i
    3. c_long(42)
    4. >>> print i.value
    5. 42
    6. >>> i.value = -99
    7. >>> print i.value
    8. -99
    9. >>>

    分配一個(gè)新的值,將指針類(lèi)型的實(shí)例c_char_p, c_wchar_p以及c_void_p改變所述存儲(chǔ)器位置它們指向,而不是內(nèi)容的內(nèi)存塊(當(dāng)然不是,因?yàn)镻ython字符串是不可變的):

    1. >>> s = "Hello, World"
    2. >>> c_s = c_char_p(s)
    3. >>> print c_s
    4. c_char_p('Hello, World')
    5. >>> c_s.value = "Hi, there"
    6. >>> print c_s
    7. c_char_p('Hi, there')
    8. >>> print s # first string is unchanged
    9. Hello, World
    10. >>>

    但是,您應(yīng)該小心,不要將它們傳遞給期望指向可變內(nèi)存的函數(shù)。如果你需要可變的內(nèi)存塊,ctypes有一個(gè)create_string_buffer()以各種方式創(chuàng)建它們的 函數(shù)。可以使用raw 屬性訪(fǎng)問(wèn)(或更改)當(dāng)前內(nèi)存塊內(nèi)容; 如果要以NUL終止字符串的形式訪(fǎng)問(wèn)它,請(qǐng)使用以下value 屬性:

    1. >>> from ctypes import *
    2. >>> p = create_string_buffer(3) # create a 3 byte buffer, initialized to NUL bytes
    3. >>> print sizeof(p), repr(p.raw)
    4. 3 '\x00\x00\x00'
    5. >>> p = create_string_buffer("Hello") # create a buffer containing a NUL terminated string
    6. >>> print sizeof(p), repr(p.raw)
    7. 6 'Hello\x00'
    8. >>> print repr(p.value)
    9. 'Hello'
    10. >>> p = create_string_buffer("Hello", 10) # create a 10 byte buffer
    11. >>> print sizeof(p), repr(p.raw)
    12. 10 'Hello\x00\x00\x00\x00\x00'
    13. >>> p.value = "Hi"
    14. >>> print sizeof(p), repr(p.raw)
    15. 10 'Hi\x00lo\x00\x00\x00\x00\x00'
    16. >>>

    create_string_buffer()函數(shù)替換了c_buffer()函數(shù)(仍可作為別名使用),以及c_string()早期ctypes版本中的函數(shù)。要?jiǎng)?chuàng)建包含C類(lèi)型的unicode字符的可變內(nèi)存塊,請(qǐng)wchar_t使用該 create_unicode_buffer()函數(shù)。

       15.17.1.5。調(diào)用函數(shù),續(xù)

    需要注意的是的printf打印到實(shí)際的標(biāo)準(zhǔn)輸出通道,給 sys.stdout,所以這些例子只是在控制臺(tái)提示符下運(yùn)行,而不是從內(nèi)IDLEPythonWin的

    1. >>> printf = libc.printf
    2. >>> printf("Hello, %s\n", "World!")
    3. Hello, World!
    4. 14
    5. >>> printf("Hello, %S\n", u"World!")
    6. Hello, World!
    7. 14
    8. >>> printf("%d bottles of beer\n", 42)
    9. 42 bottles of beer
    10. 19
    11. >>> printf("%f bottles of beer\n", 42.5)
    12. Traceback (most recent call last):
    13. File "<stdin>", line 1, in <module>
    14. ArgumentError: argument 2: exceptions.TypeError: Don't know how to convert parameter 2
    15. >>>

    如前所述,除了整數(shù),字符串和unicode字符串之外的所有Python類(lèi)型都必須包裝在相應(yīng)的ctypes類(lèi)型中,以便它們可以轉(zhuǎn)換為所需的C數(shù)據(jù)類(lèi)型:

    1. >>> printf("An int %d, a double %f\n", 1234, c_double(3.14))
    2. An int 1234, a double 3.140000
    3. 31
    4. >>>

        15.17.1.6。使用自己的自定義數(shù)據(jù)類(lèi)型調(diào)用函數(shù)

    您還可以自定義ctypes參數(shù)轉(zhuǎn)換,以允許將您自己的類(lèi)的實(shí)例用作函數(shù)參數(shù)。 ctypes查找 _as_parameter_屬性并將其用作函數(shù)參數(shù)。當(dāng)然,它必須是整數(shù),字符串或unicode之一:

    1. >>> class Bottles(object):
    2. ... def __init__(self, number):
    3. ... self._as_parameter_ = number
    4. ...
    5. >>> bottles = Bottles(42)
    6. >>> printf("%d bottles of beer\n", bottles)
    7. 42 bottles of beer
    8. 19
    9. >>>

    如果您不想將實(shí)例的數(shù)據(jù)存儲(chǔ)在_as_parameter_ 實(shí)例變量中,則可以定義property()使數(shù)據(jù)可用的數(shù)據(jù)。

       15.17.1.7。指定必需的參數(shù)類(lèi)型(函數(shù)原型)

    可以通過(guò)設(shè)置argtypes屬性來(lái)指定從DLL導(dǎo)出的函數(shù)所需的參數(shù)類(lèi)型。

    argtypes必須是一系列C數(shù)據(jù)類(lèi)型(這里的printf函數(shù)可能不是一個(gè)很好的例子,因?yàn)樗Q于格式字符串需要一個(gè)可變數(shù)字和不同類(lèi)型的參數(shù),另一方面,這對(duì)于試驗(yàn)這個(gè)特性非常方便) :

    1. >>> printf.argtypes = [c_char_p, c_char_p, c_int, c_double]
    2. >>> printf("String '%s', Int %d, Double %f\n", "Hi", 10, 2.2)
    3. String 'Hi', Int 10, Double 2.200000
    4. 37
    5. >>>

    指定格式可以防止不兼容的參數(shù)類(lèi)型(就像C函數(shù)的原型一樣),并嘗試將參數(shù)轉(zhuǎn)換為有效類(lèi)型:

    1. >>> printf("%d %d %d", 1, 2, 3)
    2. Traceback (most recent call last):
    3. File "<stdin>", line 1, in <module>
    4. ArgumentError: argument 2: exceptions.TypeError: wrong type
    5. >>> printf("%s %d %f\n", "X", 2, 3)
    6. X 2 3.000000
    7. 13
    8. >>>

    如果已經(jīng)定義了自己傳遞給函數(shù)調(diào)用的from_param()類(lèi),則必須為它們實(shí)現(xiàn)一個(gè)類(lèi)方法,以便能夠在argtypes序列中使用它們。本from_param()類(lèi)方法接收傳給函數(shù)的Python對(duì)象,它做一個(gè)類(lèi)型檢測(cè),或者是需要確保這個(gè)對(duì)象是可接受的,然后返回對(duì)象本身,它_as_parameter_不管你想傳遞的C函數(shù)屬性,或在這種情況下的論點(diǎn)。同樣,結(jié)果應(yīng)該是整數(shù),字符串,unicode,ctypes實(shí)例或具有_as_parameter_屬性的對(duì)象 。

       15.17.1.8。返回類(lèi)型

    默認(rèn)情況下,假定函數(shù)返回C int類(lèi)型。可以通過(guò)設(shè)置restype函數(shù)對(duì)象的屬性來(lái)指定其他返回類(lèi)型。

    這是一個(gè)更高級(jí)的示例,它使用strchr函數(shù),它需要一個(gè)字符串指針和一個(gè)char,并返回一個(gè)指向字符串的指針:

    1. >>> strchr = libc.strchr
    2. >>> strchr("abcdef", ord("d"))
    3. 8059983
    4. >>> strchr.restype = c_char_p # c_char_p is a pointer to a string
    5. >>> strchr("abcdef", ord("d"))
    6. 'def'
    7. >>> print strchr("abcdef", ord("x"))
    8. None
    9. >>>

    如果要避免ord("x")上面的調(diào)用,可以設(shè)置 argtypes屬性,第二個(gè)參數(shù)將從單個(gè)字符Python字符串轉(zhuǎn)換為C字符:

    1. >>> strchr.restype = c_char_p
    2. >>> strchr.argtypes = [c_char_p, c_char]
    3. >>> strchr("abcdef", "d")
    4. 'def'
    5. >>> strchr("abcdef", "def")
    6. Traceback (most recent call last):
    7. File "<stdin>", line 1, in <module>
    8. ArgumentError: argument 2: exceptions.TypeError: one character string expected
    9. >>> print strchr("abcdef", "x")
    10. None
    11. >>> strchr("abcdef", "d")
    12. 'def'
    13. >>>

    restype如果外部函數(shù)返回一個(gè)整數(shù),您還可以使用可調(diào)用的Python對(duì)象(例如函數(shù)或類(lèi))作為屬性。將使用C函數(shù)返回的整數(shù)調(diào)用callable ,并且此調(diào)用的結(jié)果將用作函數(shù)調(diào)用的結(jié)果。這對(duì)于檢查錯(cuò)誤返回值并自動(dòng)引發(fā)異常非常有用:

    1. >>> GetModuleHandle = windll.kernel32.GetModuleHandleA
    2. >>> def ValidHandle(value):
    3. ... if value == 0:
    4. ... raise WinError()
    5. ... return value
    6. ...
    7. >>>
    8. >>> GetModuleHandle.restype = ValidHandle
    9. >>> GetModuleHandle(None)
    10. 486539264
    11. >>> GetModuleHandle("something silly")
    12. Traceback (most recent call last):
    13. File "<stdin>", line 1, in <module>
    14. File "<stdin>", line 3, in ValidHandle
    15. WindowsError: [Errno 126] The specified module could not be found.
    16. >>>

    WinError是一個(gè)函數(shù),它將調(diào)用Windows FormatMessage()api來(lái)獲取錯(cuò)誤代碼的字符串表示,并返回一個(gè)異常。 WinError采用可選的錯(cuò)誤代碼參數(shù),如果沒(méi)有使用,則調(diào)用它 GetLastError()來(lái)檢索它。

    請(qǐng)注意,通過(guò)該errcheck屬性可以使用更強(qiáng)大的錯(cuò)誤檢查機(jī)制; 有關(guān)詳細(xì)信息,請(qǐng)參閱參考手冊(cè)

       15.17.1.9。傳遞指針(或:通過(guò)引用傳遞參數(shù))

    有時(shí),C api函數(shù)需要將指向數(shù)據(jù)類(lèi)型的指針作為參數(shù),可能要寫(xiě)入相應(yīng)的位置,或者數(shù)據(jù)太大而無(wú)法通過(guò)值傳遞。這也稱(chēng)為通過(guò)引用傳遞參數(shù)

    ctypes導(dǎo)出byref()用于通過(guò)引用傳遞參數(shù)的函數(shù)。使用該pointer()函數(shù)可以實(shí)現(xiàn)相同的效果 ,但是pointer()由于它構(gòu)造了一個(gè)真正的指針對(duì)象,所以工作量更大,因此byref()如果您不需要Python本身的指針對(duì)象,則使用它會(huì)更快:

    1. >>> i = c_int()
    2. >>> f = c_float()
    3. >>> s = create_string_buffer('\000' * 32)
    4. >>> print i.value, f.value, repr(s.value)
    5. 0 0.0 ''
    6. >>> libc.sscanf("1 3.14 Hello", "%d %f %s",
    7. ... byref(i), byref(f), s)
    8. 3
    9. >>> print i.value, f.value, repr(s.value)
    10. 1 3.1400001049 'Hello'
    11. >>>

       15.17.1.10。結(jié)構(gòu)和聯(lián)合

    結(jié)構(gòu)和聯(lián)合必須從導(dǎo)出StructureUnion 其中所定義的基類(lèi)ctypes模塊。每個(gè)子類(lèi)都必須定義一個(gè)_fields_屬性。 _fields_必須是2元組的列表 ,包含字段名稱(chēng)字段類(lèi)型

    字段類(lèi)型必須是ctypes類(lèi)型c_int或任何其他派生ctypes類(lèi)型:結(jié)構(gòu),聯(lián)合,數(shù)組,指針。

    下面是一個(gè)POINT結(jié)構(gòu)的簡(jiǎn)單示例,它包含兩個(gè)名為xy的整數(shù) ,還顯示了如何在構(gòu)造函數(shù)中初始化結(jié)構(gòu):

    1. >>> from ctypes import *
    2. >>> class POINT(Structure):
    3. ... _fields_ = [("x", c_int),
    4. ... ("y", c_int)]
    5. ...
    6. >>> point = POINT(10, 20)
    7. >>> print point.x, point.y
    8. 10 20
    9. >>> point = POINT(y=5)
    10. >>> print point.x, point.y
    11. 0 5
    12. >>> POINT(1, 2, 3)
    13. Traceback (most recent call last):
    14. File "<stdin>", line 1, in <module>
    15. ValueError: too many initializers
    16. >>>

    但是,您可以構(gòu)建更復(fù)雜的結(jié)構(gòu)。通過(guò)將結(jié)構(gòu)用作字段類(lèi)型,結(jié)構(gòu)本身可以包含其他結(jié)構(gòu)。

    這是一個(gè)RECT結(jié)構(gòu),它包含兩個(gè)名為upperleft和 lowerright的POINT

    1. >>> class RECT(Structure):
    2. ... _fields_ = [("upperleft", POINT),
    3. ... ("lowerright", POINT)]
    4. ...
    5. >>> rc = RECT(point)
    6. >>> print rc.upperleft.x, rc.upperleft.y
    7. 0 5
    8. >>> print rc.lowerright.x, rc.lowerright.y
    9. 0 0
    10. >>>

    嵌套結(jié)構(gòu)也可以通過(guò)以下幾種方式在構(gòu)造函數(shù)中初始化:

    1. >>> r = RECT(POINT(1, 2), POINT(3, 4))
    2. >>> r = RECT((1, 2), (3, 4))

    字段描述符 S可從被檢索類(lèi),它們可用于調(diào)試有用,因?yàn)樗鼈兛梢蕴峁┯杏玫男畔ⅲ?/p>

    1. >>> print POINT.x
    2. <Field type=c_long, ofs=0, size=4>
    3. >>> print POINT.y
    4. <Field type=c_long, ofs=4, size=4>
    5. >>>

    警告

    ctypes不支持通過(guò)值將具有位字段的聯(lián)合或結(jié)構(gòu)傳遞給函數(shù)。雖然這可能適用于32位x86,但是不能保證庫(kù)在一般情況下工作。具有位字段的聯(lián)合和結(jié)構(gòu)應(yīng)始終通過(guò)指針傳遞給函數(shù)。

       15.17.1.11。結(jié)構(gòu)/聯(lián)合對(duì)齊和字節(jié)順序

    默認(rèn)情況下,Structure和Union字段的對(duì)齊方式與C編譯器的方式相同。可以通過(guò)_pack_在子類(lèi)定義中指定類(lèi)屬性來(lái)覆蓋此行為 。必須將其設(shè)置為正整數(shù),并指定字段的最大對(duì)齊方式。這也是MSVC中的做法。#pragma pack(n)

    ctypes使用結(jié)構(gòu)和聯(lián)合的本機(jī)字節(jié)順序。要建立與非本地字節(jié)順序結(jié)構(gòu),你可以使用一個(gè) BigEndianStructureLittleEndianStructure, BigEndianUnion,和LittleEndianUnion基類(lèi)。這些類(lèi)不能包含指針字段。

       15.17.1.12。結(jié)構(gòu)和聯(lián)合中的位字段

    可以創(chuàng)建包含位字段的結(jié)構(gòu)和聯(lián)合。位字段僅適用于整數(shù)字段,位寬指定為_fields_元組中的第三項(xiàng):

    1. >>> class Int(Structure):
    2. ... _fields_ = [("first_16", c_int, 16),
    3. ... ("second_16", c_int, 16)]
    4. ...
    5. >>> print Int.first_16
    6. <Field type=c_long, ofs=0:0, bits=16>
    7. >>> print Int.second_16
    8. <Field type=c_long, ofs=0:16, bits=16>
    9. >>>

       15.17.1.13。數(shù)組

    數(shù)組是序列,包含固定數(shù)量的相同類(lèi)型的實(shí)例。

    創(chuàng)建數(shù)組類(lèi)型的推薦方法是將數(shù)據(jù)類(lèi)型與正整數(shù)相乘:

    TenPointsArrayType = POINT * 10

    這是一個(gè)有點(diǎn)人為的數(shù)據(jù)類(lèi)型的例子,一個(gè)包含4個(gè)POINT和其他東西的結(jié)構(gòu):

    1. >>> from ctypes import *
    2. >>> class POINT(Structure):
    3. ... _fields_ = ("x", c_int), ("y", c_int)
    4. ...
    5. >>> class MyStruct(Structure):
    6. ... _fields_ = [("a", c_int),
    7. ... ("b", c_float),
    8. ... ("point_array", POINT * 4)]
    9. >>>
    10. >>> print len(MyStruct().point_array)
    11. 4
    12. >>>

    通過(guò)調(diào)用類(lèi)以通常的方式創(chuàng)建實(shí)例:

    1. arr = TenPointsArrayType()
    2. for pt in arr:
    3. print pt.x, pt.y

    上面的代碼打印了一系列行,因?yàn)閿?shù)組內(nèi)容被初始化為零。0 0

    也可以指定正確類(lèi)型的初始化器:

    1. >>> from ctypes import *
    2. >>> TenIntegers = c_int * 10
    3. >>> ii = TenIntegers(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
    4. >>> print ii
    5. <c_long_Array_10 object at 0x...>
    6. >>> for i in ii: print i,
    7. ...
    8. 1 2 3 4 5 6 7 8 9 10
    9. >>>

       15.17.1.14。指針

    通過(guò)pointer()ctypes類(lèi)型上調(diào)用函數(shù) 來(lái)創(chuàng)建指針實(shí)例:

    1. >>> from ctypes import *
    2. >>> i = c_int(42)
    3. >>> pi = pointer(i)
    4. >>>

    指針實(shí)例有一個(gè)contents屬性,它返回指針指向的i對(duì)象,上面的對(duì)象:

    1. >>> pi.contents
    2. c_long(42)
    3. >>>

    注意,ctypes沒(méi)有OOR(原始對(duì)象返回),每次檢索屬性時(shí)它都會(huì)構(gòu)造一個(gè)新的等效對(duì)象:

    1. >>> pi.contents is i
    2. False
    3. >>> pi.contents is pi.contents
    4. False
    5. >>>

    將另一個(gè)c_int實(shí)例分配給指針的contents屬性會(huì)導(dǎo)致指針指向存儲(chǔ)它的內(nèi)存位置:

    1. >>> i = c_int(99)
    2. >>> pi.contents = i
    3. >>> pi.contents
    4. c_long(99)
    5. >>>

    指針實(shí)例也可以用整數(shù)索引:

    1. >>> pi[0]
    2. 99
    3. >>>

    分配整數(shù)索引會(huì)更改指向的值:

    1. >>> print i
    2. c_long(99)
    3. >>> pi[0] = 22
    4. >>> print i
    5. c_long(22)
    6. >>>

    也可以使用不同于0的索引,但您必須知道自己在做什么,就像在C中一樣:您可以訪(fǎng)問(wèn)或更改任意內(nèi)存位置。通常,如果從C函數(shù)接收指針,則只使用此功能,并且您知道指針實(shí)際指向的是數(shù)組而不是單個(gè)項(xiàng)。

    在幕后,該pointer()函數(shù)不僅僅是創(chuàng)建指針實(shí)例,還必須首先創(chuàng)建指針類(lèi)型。這是通過(guò)POINTER()接受任何ctypes類(lèi)型的函數(shù)完成的,并返回一個(gè)新類(lèi)型:

    1. >>> PI = POINTER(c_int)
    2. >>> PI
    3. <class 'ctypes.LP_c_long'>
    4. >>> PI(42)
    5. Traceback (most recent call last):
    6. File "<stdin>", line 1, in <module>
    7. TypeError: expected c_long instead of int
    8. >>> PI(c_int(42))
    9. <ctypes.LP_c_long object at 0x...>
    10. >>>

    調(diào)用不帶參數(shù)的指針類(lèi)型會(huì)創(chuàng)建NULL指針。 NULL指針有一個(gè)False布爾值:

    1. >>> null_ptr = POINTER(c_int)()
    2. >>> print bool(null_ptr)
    3. False
    4. >>>

    ctypes檢查NULL何時(shí)解除引用指針(但解除引用無(wú)效的非NULL指針會(huì)使Python崩潰):

    1. >>> null_ptr[0]
    2. Traceback (most recent call last):
    3. ....
    4. ValueError: NULL pointer access
    5. >>>
    6. >>> null_ptr[0] = 1234
    7. Traceback (most recent call last):
    8. ....
    9. ValueError: NULL pointer access
    10. >>>

       15.17.1.15。輸入轉(zhuǎn)換

    通常,ctypes會(huì)進(jìn)行嚴(yán)格的類(lèi)型檢查。這意味著,如果您 POINTER(c_int)argtypes函數(shù)列表中或在結(jié)構(gòu)定義中具有成員字段的類(lèi)型,則只接受完全相同類(lèi)型的實(shí)例。此規(guī)則有一些例外,其中ctypes接受其他對(duì)象。例如,您可以傳遞兼容的數(shù)組實(shí)例而不是指針類(lèi)型。因此,對(duì)于POINTER(c_int),ctypes接受一個(gè)c_int數(shù)組:

    1. >>> class Bar(Structure):
    2. ... _fields_ = [("count", c_int), ("values", POINTER(c_int))]
    3. ...
    4. >>> bar = Bar()
    5. >>> bar.values = (c_int * 3)(1, 2, 3)
    6. >>> bar.count = 3
    7. >>> for i in range(bar.count):
    8. ... print bar.values[i]
    9. ...
    10. 1
    11. 2
    12. 3
    13. >>>

    此外,如果函數(shù)參數(shù)顯式聲明為指針類(lèi)型(例如POINTER(c_int))in argtypes,則可以將指向類(lèi)型的對(duì)象(c_int在本例中)傳遞給函數(shù)。ctypes將自動(dòng)應(yīng)用所需的byref()轉(zhuǎn)換。

    要將POINTER類(lèi)型字段設(shè)置為NULL,您可以指定None

    1. >>> bar.values = None
    2. >>>

    有時(shí)您會(huì)遇到不兼容類(lèi)型的實(shí)例。在C中,您可以將一種類(lèi)型轉(zhuǎn)換為另一種類(lèi)型。 ctypes提供cast()可以以相同方式使用的功能。Bar上面定義的結(jié)構(gòu)接受 其字段的POINTER(c_int)指針或c_int數(shù)組values,但不接受其他類(lèi)型的實(shí)例:

    1. >>> bar.values = (c_byte * 4)()
    2. Traceback (most recent call last):
    3. File "<stdin>", line 1, in <module>
    4. TypeError: incompatible types, c_byte_Array_4 instance instead of LP_c_long instance
    5. >>>

    對(duì)于這些情況,該cast()功能很方便,cast還支持將python中的id(obj)即對(duì)象地址還原為對(duì)象

    cast()函數(shù)可用于將ctypes實(shí)例轉(zhuǎn)換為指向不同ctypes數(shù)據(jù)類(lèi)型的指針。 cast()采用兩個(gè)參數(shù),一個(gè)或者可以轉(zhuǎn)換為某種指針的ctypes對(duì)象,以及一個(gè)ctypes指針類(lèi)型。它返回第二個(gè)參數(shù)的實(shí)例,它引用與第一個(gè)參數(shù)相同的內(nèi)存塊:

    1. >>> a = (c_byte * 4)()
    2. >>> cast(a, POINTER(c_int))
    3. <ctypes.LP_c_long object at ...>
    4. >>>

    所以,cast()可以用來(lái)分配給結(jié)構(gòu)的values字段Bar

    1. >>> bar = Bar()
    2. >>> bar.values = cast((c_byte * 4)(), POINTER(c_int))
    3. >>> print bar.values[0]
    4. 0
    5. >>>

       15.17.1.16。不完全類(lèi)型

    不完整類(lèi)型是其成員尚未指定的結(jié)構(gòu),聯(lián)合或數(shù)組。在C中,它們由前向聲明指定,后面將定義:

    1. struct cell; /* forward declaration */
    2. struct cell {
    3. char *name;
    4. struct cell *next;
    5. };

    直接轉(zhuǎn)換為ctypes代碼就是這樣,但它不起作用:

    1. >>> class cell(Structure):
    2. ... _fields_ = [("name", c_char_p),
    3. ... ("next", POINTER(cell))]
    4. ...
    5. Traceback (most recent call last):
    6. File "<stdin>", line 1, in <module>
    7. File "<stdin>", line 2, in cell
    8. NameError: name 'cell' is not defined
    9. >>>

    因?yàn)閚ew 語(yǔ)句本身不可用。在,我們可以 在類(lèi)語(yǔ)句之后定義類(lèi)并設(shè)置屬性:class cellctypescell_fields_

    1. >>> from ctypes import *
    2. >>> class cell(Structure):
    3. ... pass
    4. ...
    5. >>> cell._fields_ = [("name", c_char_p),
    6. ... ("next", POINTER(cell))]
    7. >>>

    讓我們?cè)囋嚢伞N覀儎?chuàng)建了兩個(gè)實(shí)例cell,并讓它們相互指向,最后跟隨指針鏈幾次:

    1. >>> c1 = cell()
    2. >>> c1.name = "foo"
    3. >>> c2 = cell()
    4. >>> c2.name = "bar"
    5. >>> c1.next = pointer(c2)
    6. >>> c2.next = pointer(c1)
    7. >>> p = c1
    8. >>> for i in range(8):
    9. ... print p.name,
    10. ... p = p.next[0]
    11. ...
    12. foo bar foo bar foo bar foo bar
    13. >>>

       15.17.1.17。回調(diào)函數(shù)

    ctypes允許從Python callables創(chuàng)建C可調(diào)用函數(shù)指針。這些有時(shí)稱(chēng)為回調(diào)函數(shù)

    首先,您必須為回調(diào)函數(shù)創(chuàng)建一個(gè)類(lèi),該類(lèi)知道調(diào)用約定,返回類(lèi)型以及此函數(shù)將接收的參數(shù)的數(shù)量和類(lèi)型。

    CFUNCTYPE工廠(chǎng)函數(shù)使用普通的cdecl調(diào)用約定為回調(diào)函數(shù)創(chuàng)建類(lèi)型,在Windows上,WINFUNCTYPE工廠(chǎng)函數(shù)使用stdcall調(diào)用約定為回調(diào)函數(shù)創(chuàng)建類(lèi)型。

    這兩個(gè)工廠(chǎng)函數(shù)都以結(jié)果類(lèi)型作為第一個(gè)參數(shù)調(diào)用,而回調(diào)函數(shù)將期望的參數(shù)類(lèi)型作為其余參數(shù)。

    我將在這里展示一個(gè)使用標(biāo)準(zhǔn)C庫(kù)qsort() 函數(shù)的示例,它用于在回調(diào)函數(shù)的幫助下對(duì)項(xiàng)目進(jìn)行排序。 qsort()將用于對(duì)整數(shù)數(shù)組進(jìn)行排序:

    1. >>> IntArray5 = c_int * 5
    2. >>> ia = IntArray5(5, 1, 7, 33, 99)
    3. >>> qsort = libc.qsort
    4. >>> qsort.restype = None
    5. >>>

    qsort()必須使用指向要排序的數(shù)據(jù)的指針,數(shù)據(jù)數(shù)組中的項(xiàng)數(shù),一個(gè)項(xiàng)的大小以及指向比較函數(shù)(回調(diào))的指針來(lái)調(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)建:

    1. >>> CMPFUNC = CFUNCTYPE(c_int, POINTER(c_int), POINTER(c_int))
    2. >>>

    對(duì)于回調(diào)函數(shù)的第一個(gè)實(shí)現(xiàn),我們只是打印我們得到的參數(shù),并返回0(增量開(kāi)發(fā);-):

    1. >>> def py_cmp_func(a, b):
    2. ... print "py_cmp_func", a, b
    3. ... return 0
    4. ...
    5. >>>

    創(chuàng)建C可調(diào)用回調(diào):

    1. >>> cmp_func = CMPFUNC(py_cmp_func)
    2. >>>

    我們準(zhǔn)備好了:

    1. >>> qsort(ia, len(ia), sizeof(c_int), cmp_func)
    2. py_cmp_func <ctypes.LP_c_long object at 0x00...> <ctypes.LP_c_long object at 0x00...>
    3. py_cmp_func <ctypes.LP_c_long object at 0x00...> <ctypes.LP_c_long object at 0x00...>
    4. py_cmp_func <ctypes.LP_c_long object at 0x00...> <ctypes.LP_c_long object at 0x00...>
    5. py_cmp_func <ctypes.LP_c_long object at 0x00...> <ctypes.LP_c_long object at 0x00...>
    6. py_cmp_func <ctypes.LP_c_long object at 0x00...> <ctypes.LP_c_long object at 0x00...>
    7. py_cmp_func <ctypes.LP_c_long object at 0x00...> <ctypes.LP_c_long object at 0x00...>
    8. py_cmp_func <ctypes.LP_c_long object at 0x00...> <ctypes.LP_c_long object at 0x00...>
    9. py_cmp_func <ctypes.LP_c_long object at 0x00...> <ctypes.LP_c_long object at 0x00...>
    10. py_cmp_func <ctypes.LP_c_long object at 0x00...> <ctypes.LP_c_long object at 0x00...>
    11. py_cmp_func <ctypes.LP_c_long object at 0x00...> <ctypes.LP_c_long object at 0x00...>
    12. >>>

    我們知道如何訪(fǎng)問(wèn)指針的內(nèi)容,所以讓我們重新定義我們的回調(diào):

    1. >>> def py_cmp_func(a, b):
    2. ... print "py_cmp_func", a[0], b[0]
    3. ... return 0
    4. ...
    5. >>> cmp_func = CMPFUNC(py_cmp_func)
    6. >>>

    以下是我們?cè)赪indows上獲得的內(nèi)容:

    1. >>> qsort(ia, len(ia), sizeof(c_int), cmp_func)
    2. py_cmp_func 7 1
    3. py_cmp_func 33 1
    4. py_cmp_func 99 1
    5. py_cmp_func 5 1
    6. py_cmp_func 7 5
    7. py_cmp_func 33 5
    8. py_cmp_func 99 5
    9. py_cmp_func 7 99
    10. py_cmp_func 33 99
    11. py_cmp_func 7 33
    12. >>>

    很有趣的是,在linux上,sort函數(shù)看起來(lái)效率更高,它做的比較少:

    1. >>> qsort(ia, len(ia), sizeof(c_int), cmp_func)
    2. py_cmp_func 5 1
    3. py_cmp_func 33 99
    4. py_cmp_func 7 33
    5. py_cmp_func 5 7
    6. py_cmp_func 1 7
    7. >>>

    啊,我們差不多完成了!最后一步是實(shí)際比較這兩個(gè)項(xiàng)并返回一個(gè)有用的結(jié)果:

    1. >>> def py_cmp_func(a, b):
    2. ... print "py_cmp_func", a[0], b[0]
    3. ... return a[0] - b[0]
    4. ...
    5. >>>

    最終在Windows上運(yùn)行:

    1. >>> qsort(ia, len(ia), sizeof(c_int), CMPFUNC(py_cmp_func))
    2. py_cmp_func 33 7
    3. py_cmp_func 99 33
    4. py_cmp_func 5 99
    5. py_cmp_func 1 99
    6. py_cmp_func 33 7
    7. py_cmp_func 1 33
    8. py_cmp_func 5 33
    9. py_cmp_func 5 7
    10. py_cmp_func 1 7
    11. py_cmp_func 5 1
    12. >>>

    在Linux上:

    1. >>> qsort(ia, len(ia), sizeof(c_int), CMPFUNC(py_cmp_func))
    2. py_cmp_func 5 1
    3. py_cmp_func 33 99
    4. py_cmp_func 7 33
    5. py_cmp_func 1 7
    6. py_cmp_func 5 7
    7. >>>

    很有趣的是,Windows qsort()功能需要比Linux版本更多的比較!

    我們可以輕松檢查,我們的數(shù)組現(xiàn)在排序:

    1. >>> for i in ia: print i,
    2. ...
    3. 1 5 7 33 99
    4. >>>

    注意

    CFUNCTYPE()只要從C代碼中使用對(duì)象,請(qǐng)確保保留對(duì)對(duì)象的引用。ctypes沒(méi)有,如果你不這樣做,它們可能被垃圾收集,在回調(diào)時(shí)崩潰你的程序。

    另外,請(qǐng)注意,如果在Python控件之外創(chuàng)建的線(xiàn)程中調(diào)用回調(diào)函數(shù)(例如,通過(guò)調(diào)用回調(diào)的外部代碼),ctypes會(huì)在每次調(diào)用時(shí)創(chuàng)建一個(gè)新的虛擬Python線(xiàn)程。這種行為是對(duì)大多數(shù)的目的是正確的,但它意味著存儲(chǔ)的值threading.local不會(huì)在不同的回調(diào)生存,即使這些電話(huà)是從同一個(gè)C的線(xiàn)。

       15.17.1.18。訪(fǎng)問(wèn)從dll導(dǎo)出的值

    一些共享庫(kù)不僅導(dǎo)出函數(shù),還導(dǎo)出變量。Python庫(kù)本身的一個(gè)示例是Py_OptimizeFlag,一個(gè)設(shè)置為0,1或2的整數(shù),具體取決于啟動(dòng)時(shí)給出的-O-OO標(biāo)志。

    ctypes可以使用in_dll()類(lèi)型的類(lèi)方法訪(fǎng)問(wèn)這樣的值。 pythonapi是一個(gè)預(yù)定義的符號(hào),可以訪(fǎng)問(wèn)Python C api:

    1. >>> opt_flag = c_int.in_dll(pythonapi, "Py_OptimizeFlag")
    2. >>> print opt_flag
    3. c_long(0)
    4. >>>

    如果解釋器已經(jīng)啟動(dòng)-O,則樣本將打印c_long(1),或者c_long(2)如果-OO已經(jīng)指定。

    一個(gè)擴(kuò)展示例也演示了指針的使用,可以訪(fǎng)問(wèn)PyImport_FrozenModulesPython導(dǎo)出的 指針。

    引用Python文檔:此指針初始化為指向“struct _frozen”記錄的數(shù)組,由其成員全部為NULL或零的記錄終止。導(dǎo)入凍結(jié)模塊時(shí),將在此表中搜索它。第三方代碼可以使用此方法來(lái)提供動(dòng)態(tài)創(chuàng)建的凍結(jié)模塊集合。

    所以操縱這個(gè)指針甚至可以證明是有用的。為了限制示例大小,我們僅顯示如何使用以下方法讀取此表ctypes

    1. >>> from ctypes import *
    2. >>>
    3. >>> class struct_frozen(Structure):
    4. ... _fields_ = [("name", c_char_p),
    5. ... ("code", POINTER(c_ubyte)),
    6. ... ("size", c_int)]
    7. ...
    8. >>>

    我們已經(jīng)定義了數(shù)據(jù)類(lèi)型,因此我們可以獲得指向表的指針:struct _frozen

    1. >>> FrozenTable = POINTER(struct_frozen)
    2. >>> table = FrozenTable.in_dll(pythonapi, "PyImport_FrozenModules")
    3. >>>

    因?yàn)?code>table是一個(gè)記錄pointer數(shù)組struct_frozen,我們可以迭代它,但我們必須確保我們的循環(huán)終止,因?yàn)橹羔槢](méi)有大小。遲早它可能會(huì)因訪(fǎng)問(wèn)沖突或其他原因而崩潰,所以當(dāng)我們點(diǎn)擊NULL條目時(shí)最好突破循環(huán):

    1. >>> for item in table:
    2. ... print item.name, item.size
    3. ... if item.name is None:
    4. ... break
    5. ...
    6. __hello__ 104
    7. __phello__ -104
    8. __phello__.spam 104
    9. None 0
    10. >>>

    標(biāo)準(zhǔn)Python具有凍結(jié)模塊和凍結(jié)包(由負(fù)大小成員指示)的事實(shí)并不為人所知,它僅用于測(cè)試。例如嘗試一下。import __hello__

       15.17.1.19。驚喜

    在某些邊緣情況下ctypes,您可能會(huì)發(fā)現(xiàn)實(shí)際情況以外的其他情況。

    請(qǐng)考慮以下示例:

    1. >>> from ctypes import *
    2. >>> class POINT(Structure):
    3. ... _fields_ = ("x", c_int), ("y", c_int)
    4. ...
    5. >>> class RECT(Structure):
    6. ... _fields_ = ("a", POINT), ("b", POINT)
    7. ...
    8. >>> p1 = POINT(1, 2)
    9. >>> p2 = POINT(3, 4)
    10. >>> rc = RECT(p1, p2)
    11. >>> print rc.a.x, rc.a.y, rc.b.x, rc.b.y
    12. 1 2 3 4
    13. >>> # now swap the two points
    14. >>> rc.a, rc.b = rc.b, rc.a
    15. >>> print rc.a.x, rc.a.y, rc.b.x, rc.b.y
    16. 3 4 3 4
    17. >>>

    嗯。我們當(dāng)然希望打印最后一份聲明。發(fā)生了什么?以下是上述行的步驟:3 4 1 2rc.a, rc.b = rc.b, rc.a

    1. >>> temp0, temp1 = rc.b, rc.a
    2. >>> rc.a = temp0
    3. >>> rc.b = temp1
    4. >>>

    請(qǐng)注意,temp0并且temp1還在使用的內(nèi)部緩沖器的對(duì)象rc上述對(duì)象。因此執(zhí)行將緩沖區(qū)內(nèi)容復(fù)制到緩沖區(qū)中。反過(guò)來(lái),這改變了內(nèi)容。因此,最后一項(xiàng)任務(wù),沒(méi)有預(yù)期的效果。rc.a = temp0temp0rctemp1rc.b = temp1

    請(qǐng)記住,從Structure,Unions和Arrays中檢索子對(duì)象不會(huì)復(fù)制子對(duì)象,而是檢索訪(fǎng)問(wèn)根對(duì)象底層緩沖區(qū)的包裝器對(duì)象。

    另一個(gè)可能與預(yù)期不同的例子是:

    1. >>> s = c_char_p()
    2. >>> s.value = "abc def ghi"
    3. >>> s.value
    4. 'abc def ghi'
    5. >>> s.value is s.value
    6. False
    7. >>>

    為什么打印False?ctypes實(shí)例是包含內(nèi)存塊的對(duì)象以及訪(fǎng)問(wèn)內(nèi)存內(nèi)容的一些描述符。在內(nèi)存塊中存儲(chǔ)Python對(duì)象不會(huì)存儲(chǔ)對(duì)象本身,而是存儲(chǔ)對(duì)象contents的對(duì)象。再次訪(fǎng)問(wèn)內(nèi)容每次構(gòu)造一個(gè)新的Python對(duì)象!

       15.17.1.20。可變大小的數(shù)據(jù)類(lèi)型

    ctypes 為可變大小的數(shù)組和結(jié)構(gòu)提供了一些支持。

    resize()函數(shù)可用于調(diào)整現(xiàn)有ctypes對(duì)象的內(nèi)存緩沖區(qū)的大小。該函數(shù)將對(duì)象作為第一個(gè)參數(shù),并將請(qǐng)求的大小(以字節(jié)為單位)作為第二個(gè)參數(shù)。內(nèi)存塊不能小于對(duì)象類(lèi)型指定的自然內(nèi)存塊,ValueError如果嘗試,則引發(fā)a :

    1. >>> short_array = (c_short * 4)()
    2. >>> print sizeof(short_array)
    3. 8
    4. >>> resize(short_array, 4)
    5. Traceback (most recent call last):
    6. ...
    7. ValueError: minimum size is 8
    8. >>> resize(short_array, 32)
    9. >>> sizeof(short_array)
    10. 32
    11. >>> sizeof(type(short_array))
    12. 8
    13. >>>

    這很好很好,但是如何訪(fǎng)問(wèn)此數(shù)組中包含的其他元素?由于類(lèi)型仍然只知道4個(gè)元素,因此訪(fǎng)問(wèn)其他元素時(shí)會(huì)出錯(cuò):

    1. >>> short_array[:]
    2. [0, 0, 0, 0]
    3. >>> short_array[7]
    4. Traceback (most recent call last):
    5. ...
    6. IndexError: invalid index
    7. >>>

    使用可變大小數(shù)據(jù)類(lèi)型的另一種方法ctypes是使用Python的動(dòng)態(tài)特性,并且在已知所需大小之后(根據(jù)具體情況)重新定義數(shù)據(jù)類(lèi)型。

      15.17.2。ctypes引用

      15.17.2.1。查找共享庫(kù)

    使用編譯語(yǔ)言編程時(shí),在編譯/鏈接程序時(shí)以及程序運(yùn)行時(shí)都會(huì)訪(fǎng)問(wèn)共享庫(kù)。

    find_library()函數(shù)的目的是以類(lèi)似于編譯器的方式定位庫(kù)(在具有多個(gè)版本的共享庫(kù)的平臺(tái)上應(yīng)該加載最新版本),而ctypes庫(kù)加載器就像程序運(yùn)行時(shí)一樣,并直接調(diào)用運(yùn)行時(shí)加載程序。

    ctypes.util模塊提供了一個(gè)函數(shù),可以幫助確定要加載的庫(kù)。

    ctypes.util.find_library姓名

    嘗試查找?guī)觳⒎祷芈窂矫?nbsp;名字是不一樣的任何前綴庫(kù)名的lib,標(biāo)的相同.so.dylib或版本號(hào)(這是用于POSIX鏈接器選項(xiàng)的形式-l)。如果找不到庫(kù),則返回None

    確切的功能取決于系統(tǒng)。

    在Linux上,find_library()嘗試運(yùn)行外部程序(/sbin/ldconfiggcc,和objdump)找到庫(kù)文件。它返回庫(kù)文件的文件名。這里有些例子:

    1. >>> from ctypes.util import find_library
    2. >>> find_library("m")
    3. 'libm.so.6'
    4. >>> find_library("c")
    5. 'libc.so.6'
    6. >>> find_library("bz2")
    7. 'libbz2.so.1.0'
    8. >>>

    在OS X上,find_library()嘗試幾個(gè)預(yù)定義的命名方案和路徑來(lái)定位庫(kù),如果成功則返回完整路徑名:

    1. >>> from ctypes.util import find_library
    2. >>> find_library("c")
    3. '/usr/lib/libc.dylib'
    4. >>> find_library("m")
    5. '/usr/lib/libm.dylib'
    6. >>> find_library("bz2")
    7. '/usr/lib/libbz2.dylib'
    8. >>> find_library("AGL")
    9. '/System/Library/Frameworks/AGL.framework/AGL'
    10. >>>

    在Windows上,find_library()沿系統(tǒng)搜索路徑進(jìn)行搜索,并返回完整路徑名,但由于沒(méi)有預(yù)定義的命名方案,因此調(diào)用find_library("c")將失敗并返回None

    如果包裝共享庫(kù)ctypes,它可以更好地確定在開(kāi)發(fā)時(shí)共享庫(kù)的名字,并硬編碼到封裝模塊,而不是使用find_library()定位在運(yùn)行時(shí)庫(kù)。

       15.17.2.2。加載共享庫(kù)

    有幾種方法可以將共享庫(kù)加載到Python進(jìn)程中。一種方法是實(shí)例化以下類(lèi)之一:

    class ctypes.CDLLnamemode = DEFAULT_MODEhandle = Noneuse_errno = Falseuse_last_error = False 

    此類(lèi)的實(shí)例表示已加載的共享庫(kù)。這些庫(kù)中的函數(shù)使用標(biāo)準(zhǔn)C調(diào)用約定,并假定返回 int

    class ctypes.OleDLLnamemode = DEFAULT_MODEhandle = Noneuse_errno = Falseuse_last_error = False 

    僅限Windows:此類(lèi)的實(shí)例表示已加載的共享庫(kù),這些庫(kù)中的函數(shù)使用stdcall調(diào)用約定,并假定返回特定于Windows的HRESULT代碼。 HRESULT values包含指定函數(shù)調(diào)用是否失敗或成功的信息,以及其他錯(cuò)誤代碼。如果返回值表示失敗,WindowsError則自動(dòng)引發(fā)a。

    class ctypes.WinDLLnamemode = DEFAULT_MODEhandle = Noneuse_errno = Falseuse_last_error = False 

    僅限Windows:此類(lèi)的實(shí)例表示已加載的共享庫(kù),這些庫(kù)中的函數(shù)使用stdcall調(diào)用約定,并且int默認(rèn)情況下假定返回。

    在Windows CE上,僅使用標(biāo)準(zhǔn)調(diào)用約定,以方便 WinDLLOleDLL使用此平臺(tái)上的標(biāo)準(zhǔn)調(diào)用約定。

    Python 全局解釋器鎖在調(diào)用這些庫(kù)導(dǎo)出的任何函數(shù)之前發(fā)布,之后重新獲取。

    class ctypes.PyDLLnamemode = DEFAULT_MODEhandle = None 

    CDLL除了在函數(shù)調(diào)用期間釋放Python GIL之外,此類(lèi)的實(shí)例的行為與實(shí)例類(lèi)似,并且在函數(shù)執(zhí)行之后,將檢查Python錯(cuò)誤標(biāo)志。如果設(shè)置了錯(cuò)誤標(biāo)志,則會(huì)引發(fā)Python異常。

    因此,這僅對(duì)直接調(diào)用Python C api函數(shù)有用。

    所有這些類(lèi)都可以通過(guò)使用至少一個(gè)參數(shù)(共享庫(kù)的路徑名)調(diào)用它們來(lái)實(shí)例化。如果已有已加載的共享庫(kù)的現(xiàn)有句柄,則可以將其作為handle命名參數(shù)傳遞,否則使用基礎(chǔ)平臺(tái)dlopenLoadLibrary 函數(shù)將庫(kù)加載到進(jìn)程中,并獲取它的句柄。

    模式參數(shù)可用于指定庫(kù)的加載方式。有關(guān)詳細(xì)信息,請(qǐng)參閱dlopen(3)聯(lián)機(jī)幫助頁(yè)。在Windows上,模式被忽略。在posix系統(tǒng)上,始終添加RTLD_NOW,并且不可配置。

    use_errno參數(shù),當(dāng)設(shè)置為true,使一個(gè)ctypes機(jī)制,允許訪(fǎng)問(wèn)該系統(tǒng)errno以安全的方式錯(cuò)誤號(hào)。 ctypes維護(hù)系統(tǒng)errno 變量的線(xiàn)程局部副本; 如果在函數(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()用于請(qǐng)求和更改Windows錯(cuò)誤代碼的ctypes私有副本。

    新的2.6版:use_last_erroruse_errno可選參數(shù)添加。

    ctypes.RTLD_GLOBAL

    用作模式參數(shù)的標(biāo)志。在此標(biāo)志不可用的平臺(tái)上,它被定義為整數(shù)零。

    ctypes.RTLD_LOCAL

    用作模式參數(shù)的標(biāo)志。在沒(méi)有此功能的平臺(tái)上,它與RTLD_GLOBAL相同。

    ctypes.DEFAULT_MODE

    用于加載共享庫(kù)的默認(rèn)模式。在OSX 10.3上,這是 RTLD_GLOBAL,否則它與RTLD_LOCAL相同。

    這些類(lèi)的實(shí)例沒(méi)有公共方法。共享庫(kù)導(dǎo)出的函數(shù)可以作為屬性或索引進(jìn)行訪(fǎng)問(wèn)。請(qǐng)注意,通過(guò)屬性訪(fǎng)問(wèn)函數(shù)會(huì)緩存結(jié)果,因此每次重復(fù)訪(fǎng)問(wèn)它都會(huì)返回相同的對(duì)象。另一方面,通過(guò)索引訪(fǎng)問(wèn)它每次都會(huì)返回一個(gè)新對(duì)象:

    1. >>> libc.time == libc.time
    2. True
    3. >>> libc['time'] == libc['time']
    4. False

    可以使用以下公共屬性,它們的名稱(chēng)以下劃線(xiàn)開(kāi)頭,以便不與導(dǎo)出的函數(shù)名沖突:

    PyDLL._handle

    用于訪(fǎng)問(wèn)庫(kù)的系統(tǒng)句柄。

    PyDLL._name

    在構(gòu)造函數(shù)中傳遞的庫(kù)的名稱(chēng)。

    還可以使用其中一個(gè)預(yù)制對(duì)象(LibraryLoader通過(guò)調(diào)用 LoadLibrary()方法)或通過(guò)將庫(kù)檢索為加載程序?qū)嵗膶傩詠?lái)加載共享庫(kù)。

    class ctypes.LibraryLoaderdlltype 

    加載共享庫(kù)的類(lèi)。 dlltype應(yīng)該是一個(gè) CDLLPyDLLWinDLLOleDLL類(lèi)型。

    __getattr__()具有特殊行為:它允許通過(guò)將其作為庫(kù)加載器實(shí)例的屬性訪(fǎng)問(wèn)來(lái)加載共享庫(kù)。結(jié)果是緩存的,因此重復(fù)的屬性訪(fǎng)問(wèn)每次都返回相同的庫(kù)。

    LoadLibrary名字

    將共享庫(kù)加載到進(jìn)程中并返回它。此方法始終返回庫(kù)的新實(shí)例。

    這些預(yù)制庫(kù)加載器可用:

    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í)例。

    為了直接訪(fǎng)問(wèn)C Python api,可以使用現(xiàn)成的Python共享庫(kù)對(duì)象:

    ctypes.pythonapi

    它的一個(gè)實(shí)例PyDLL將Python C API函數(shù)公開(kāi)為屬性。請(qǐng)注意,假設(shè)所有這些函數(shù)都返回C int,這當(dāng)然不總是事實(shí),因此您必須分配正確的restype屬性才能使用這些函數(shù)。

       15.17.2.3。外來(lái)函數(shù)

    如前一節(jié)所述,外部函數(shù)可以作為加載的共享庫(kù)的屬性進(jìn)行訪(fǎng)問(wèn)。默認(rèn)情況下以這種方式創(chuàng)建的函數(shù)對(duì)象接受任意數(shù)量的參數(shù),接受任何ctypes數(shù)據(jù)實(shí)例作為參數(shù),并返回庫(kù)加載器指定的默認(rèn)結(jié)果類(lèi)型。他們是私人班級(jí)的實(shí)例:

    類(lèi)ctypes._FuncPtr

    C可調(diào)用外部函數(shù)的基類(lèi)。

    外部函數(shù)的實(shí)例也是C兼容的數(shù)據(jù)類(lèi)型; 它們代表C函數(shù)指針。

    可以通過(guò)分配外部函數(shù)對(duì)象的特殊屬性來(lái)自定義此行為。

    restype

    指定ctypes類(lèi)型以指定外部函數(shù)的結(jié)果類(lèi)型。使用Nonevoid,功能不返回任何東西。

    可以分配不是ctypes類(lèi)型的可調(diào)用Python對(duì)象,在這種情況下假定函數(shù)返回C int,并且將使用此整數(shù)調(diào)用callable,從而允許進(jìn)一步處理或錯(cuò)誤檢查。不推薦使用它,為了更靈活的后處理或錯(cuò)誤檢查,請(qǐng)使用ctypes數(shù)據(jù)類(lèi)型, restype并為該errcheck屬性分配一個(gè)callable 。

    argtypes

    分配ctypes類(lèi)型的元組以指定函數(shù)接受的參數(shù)類(lèi)型。使用stdcall調(diào)用約定的函數(shù)只能使用與此元組的長(zhǎng)度相同的參數(shù)數(shù)來(lái)調(diào)用; 使用C調(diào)用約定的函數(shù)也接受其他未指定的參數(shù)。

    當(dāng)調(diào)用外部函數(shù)時(shí),每個(gè)實(shí)際參數(shù)都傳遞給 元組中from_param()項(xiàng)的 類(lèi)方法argtypes,此方法允許將實(shí)際參數(shù)調(diào)整為外部函數(shù)接受的對(duì)象。例如,元組中的c_char_p項(xiàng)argtypes將使用ctypes轉(zhuǎn)換規(guī)則將作為參數(shù)傳遞的unicode字符串轉(zhuǎn)換為字節(jié)字符串。

    新增:現(xiàn)在可以將項(xiàng)目放在不是ctypes類(lèi)型的argtypes中,但每個(gè)項(xiàng)目必須有一個(gè)from_param()返回可用作參數(shù)的值的方法(整數(shù),字符串,ctypes實(shí)例)。這允許定義可以將自定義對(duì)象調(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ù)對(duì)象本身,這允許重用相同的可調(diào)用對(duì)象來(lái)檢查或后處理幾個(gè)函數(shù)的結(jié)果。

    arguments是一個(gè)包含最初傳遞給函數(shù)調(diào)用的參數(shù)的元組,這允許對(duì)所使用的參數(shù)進(jìn)行特殊處理。

    此函數(shù)返回的對(duì)象將從外部函數(shù)調(diào)用返回,但如果外部函數(shù)調(diào)用失敗,它還可以檢查結(jié)果值并引發(fā)異常。

    異常ctypes.ArgumentError

    當(dāng)外部函數(shù)調(diào)用無(wú)法轉(zhuǎn)換其中一個(gè)傳遞的參數(shù)時(shí),會(huì)引發(fā)此異常。

       15.17.2.4。函數(shù)原型

    也可以通過(guò)實(shí)例化函數(shù)原型來(lái)創(chuàng)建外部函數(shù)。函數(shù)原型類(lèi)似于C中的函數(shù)原型; 它們描述了一個(gè)函數(shù)(返回類(lèi)型,參數(shù)類(lèi)型,調(diào)用約定)而沒(méi)有定義實(shí)現(xiàn)。必須使用所需的結(jié)果類(lèi)型和函數(shù)的參數(shù)類(lèi)型調(diào)用工廠(chǎng)函數(shù)。

    ctypes.CFUNCTYPErestype* argtypesuse_errno = Falseuse_last_error = False 

    返回的函數(shù)原型創(chuàng)建使用標(biāo)準(zhǔn)C調(diào)用約定的函數(shù)。該功能將在通話(huà)期間釋放GIL。如果 use_errno設(shè)置為true,則系統(tǒng)errno變量的ctypes私有副本將 與errno調(diào)用前后的實(shí)際值進(jìn)行交換; use_last_error對(duì)Windows錯(cuò)誤代碼執(zhí)行相同操作。

    版本2.6中已更改:添加了可選的use_errnouse_last_error參數(shù)。

    ctypes.WINFUNCTYPErestype* argtypesuse_errno = Falseuse_last_error = False 

    僅適用于Windows:返回的函數(shù)原型創(chuàng)建使用函數(shù) stdcall調(diào)用約定,除了Windows CE地方 WINFUNCTYPE()是一樣的CFUNCTYPE()。該功能將在通話(huà)期間釋放GIL。 use_errnouse_last_error具有與上面相同的含義。

    ctypes.PYFUNCTYPErestype* argtypes 

    返回的函數(shù)原型創(chuàng)建使用Python調(diào)用約定的函數(shù)。該功能在通話(huà)期間不會(huì)釋放GIL。

    由這些工廠(chǎng)函數(shù)創(chuàng)建的函數(shù)原型可以以不同的方式實(shí)例化,具體取決于調(diào)用中參數(shù)的類(lèi)型和數(shù)量:

    prototype地址

    返回指定地址的外部函數(shù),該函數(shù)必須是整數(shù)。

    prototype可贖回

    從Python 可調(diào)用創(chuàng)建C可調(diào)用函數(shù)(回調(diào)函數(shù))。

    prototypefunc_spec [,paramflags ] )

    返回由共享庫(kù)導(dǎo)出的外部函數(shù)。func_spec必須是2元組。第一項(xiàng)是導(dǎo)出函數(shù)的名稱(chēng)作為字符串,或?qū)С龊瘮?shù)的序號(hào)作為小整數(shù)。第二項(xiàng)是共享庫(kù)實(shí)例。(name_or_ordinal, library)

    prototypevtbl_indexname [,paramflags [,iid ] ] )

    返回將調(diào)用COM方法的外部函數(shù)。vtbl_index是虛函數(shù)表的索引,是一個(gè)小的非負(fù)整數(shù)。name是COM方法的名稱(chēng)。iid是指向擴(kuò)展錯(cuò)誤報(bào)告中使用的接口標(biāo)識(shí)符的可選指針。

    COM方法使用特殊的調(diào)用約定:除了argtypes元組中指定的那些參數(shù)外,它們還需要指向COM接口的指針作為第一個(gè)參數(shù)。

    可選的paramflags參數(shù)創(chuàng)建的外部函數(shù)包裝器具有比上述功能更多的功能。

    paramflags必須是一個(gè)長(zhǎng)度相同的元組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ù)。外來(lái)函數(shù)填入一個(gè)值。

    4

    輸入?yún)?shù),默認(rèn)為整數(shù)零。

    可選的第二項(xiàng)是參數(shù)名稱(chēng)為字符串。如果指定了此參數(shù),則可以使用命名參數(shù)調(diào)用外部函數(shù)。

    可選的第三項(xiàng)是此參數(shù)的默認(rèn)值。

    此示例演示如何包裝Windows MessageBoxA函數(shù),以便它支持默認(rèn)參數(shù)和命名參數(shù)。Windows頭文件中的C聲明是這樣的:

    1. WINUSERAPI int WINAPI
    2. MessageBoxA(
    3. HWND hWnd,
    4. LPCSTR lpText,
    5. LPCSTR lpCaption,
    6. UINT uType);

    這是包裝ctypes

    1. >>> from ctypes import c_int, WINFUNCTYPE, windll
    2. >>> from ctypes.wintypes import HWND, LPCSTR, UINT
    3. >>> prototype = WINFUNCTYPE(c_int, HWND, LPCSTR, LPCSTR, UINT)
    4. >>> paramflags = (1, "hwnd", 0), (1, "text", "Hi"), (1, "caption", None), (1, "flags", 0)
    5. >>> MessageBox = prototype(("MessageBoxA", windll.user32), paramflags)
    6. >>>

    現(xiàn)在可以通過(guò)以下方式調(diào)用MessageBox外部函數(shù):

    1. >>> MessageBox()
    2. >>> MessageBox(text="Spam, spam, spam")
    3. >>> MessageBox(flags=2, text="foo bar")
    4. >>>

    第二個(gè)例子演示了輸出參數(shù)。win32 GetWindowRect 函數(shù)通過(guò)將指定窗口的尺寸復(fù)制到RECT調(diào)用者必須提供的結(jié)構(gòu)中來(lái)檢索它們的尺寸 。這是C聲明:

    1. WINUSERAPI BOOL WINAPI
    2. GetWindowRect(
    3. HWND hWnd,
    4. LPRECT lpRect);

    這是包裝ctypes

    1. >>> from ctypes import POINTER, WINFUNCTYPE, windll, WinError
    2. >>> from ctypes.wintypes import BOOL, HWND, RECT
    3. >>> prototype = WINFUNCTYPE(BOOL, HWND, POINTER(RECT))
    4. >>> paramflags = (1, "hwnd"), (2, "lprect")
    5. >>> GetWindowRect = prototype(("GetWindowRect", windll.user32), paramflags)
    6. >>>

    具有輸出參數(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 GetWindowRectapi函數(shù)返回一個(gè)BOOL指示成功或失敗的信號(hào),因此該函數(shù)可以執(zhí)行錯(cuò)誤檢查,并在api調(diào)用失敗時(shí)引發(fā)異常:

    1. >>> def errcheck(result, func, args):
    2. ... if not result:
    3. ... raise WinError()
    4. ... return args
    5. ...
    6. >>> GetWindowRect.errcheck = errcheck
    7. >>>

    如果errcheck函數(shù)返回參數(shù)tuple,它接收不變,ctypes繼續(xù)對(duì)輸出參數(shù)進(jìn)行的正常處理。如果要返回窗口坐標(biāo)而不是RECT實(shí)例的元組 ,可以檢索函數(shù)中的字段并返回它們,將不再進(jìn)行正常處理:

    1. >>> def errcheck(result, func, args):
    2. ... if not result:
    3. ... raise WinError()
    4. ... rc = args[1]
    5. ... return rc.left, rc.top, rc.bottom, rc.right
    6. ...
    7. >>> GetWindowRect.errcheck = errcheck
    8. >>>

       15.17.2.5。實(shí)用功能

    ctypes.addressofobj 

    以整數(shù)形式返回內(nèi)存緩沖區(qū)的地址。 obj必須是ctypes類(lèi)型的實(shí)例。

    ctypes.alignmentobj_or_type 

    返回ctypes類(lèi)型的對(duì)齊要求。obj_or_type必須是ctypes類(lèi)型或?qū)嵗?/p>

    ctypes.byrefobj [,offset ] )

    返回一個(gè)指向obj的輕量級(jí)指針,該指針必須是ctypes類(lèi)型的一個(gè)實(shí)例。 offset默認(rèn)為零,并且必須是將添加到內(nèi)部指針值的整數(shù)。

    byref(obj, offset) 對(duì)應(yīng)于此C代碼:

    (((char *)&obj) + offset)

    返回的對(duì)象只能用作外部函數(shù)調(diào)用參數(shù)。它的行為類(lèi)似pointer(obj),但構(gòu)造速度要快得多。

    :在2.6版本中的新偏移添加可選的參數(shù)。

    ctypes.castobjtype 

    此函數(shù)類(lèi)似于C中的強(qiáng)制轉(zhuǎn)換運(yùn)算符。它返回一個(gè)新的類(lèi)型實(shí)例,它指向與obj相同的內(nèi)存塊。 type 必須是指針類(lèi)型,obj必須是可以解釋為指針的對(duì)象。

    ctypes.create_string_bufferinit_or_size [,size ] )

    此函數(shù)創(chuàng)建一個(gè)可變字符緩沖區(qū)。返回的對(duì)象是ctypes數(shù)組c_char

    init_or_size必須是一個(gè)整數(shù),它指定數(shù)組的大小,或者是一個(gè)用于初始化數(shù)組項(xiàng)的字符串。

    如果將字符串指定為第一個(gè)參數(shù),則將緩沖區(qū)設(shè)置為大于字符串長(zhǎng)度的一個(gè)項(xiàng)目,以便數(shù)組中的最后一個(gè)元素是NUL終止字符。可以將整數(shù)作為第二個(gè)參數(shù)傳遞,如果不應(yīng)使用字符串的長(zhǎng)度,則允許指定數(shù)組的大小。

    如果第一個(gè)參數(shù)是unicode字符串,則根據(jù)ctypes轉(zhuǎn)換規(guī)則將其轉(zhuǎn)換為8位字符串。

    ctypes.create_unicode_bufferinit_or_size [,size ] )

    此函數(shù)創(chuàng)建一個(gè)可變的unicode字符緩沖區(qū)。返回的對(duì)象是ctypes數(shù)組c_wchar

    init_or_size必須是指定數(shù)組大小的整數(shù),或者是用于初始化數(shù)組項(xiàng)的unicode字符串。

    如果將unicode字符串指定為第一個(gè)參數(shù),則將緩沖區(qū)設(shè)置為大于字符串長(zhǎng)度的一個(gè)項(xiàng)目,以便數(shù)組中的最后一個(gè)元素是NUL終止字符。可以將整數(shù)作為第二個(gè)參數(shù)傳遞,如果不應(yīng)使用字符串的長(zhǎ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是沒(méi)有任何前綴的庫(kù)名,如lib后綴.so.dylib或版本號(hào)(這是用于posix鏈接器選項(xiàng)的形式-l)。如果找不到庫(kù),則返回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í)庫(kù)的文件名,以及擴(kuò)展模塊。如果無(wú)法確定庫(kù)的名稱(chēng),None則返回。

    如果需要釋放內(nèi)存,例如,由擴(kuò)展模塊調(diào)用的內(nèi)存,則必須在分配內(nèi)存的同一庫(kù)中使用該功能。free(void *)

    版本2.6中的新功能。

    ctypes.FormatError([ code ] )

    僅適用于Windows:返回的錯(cuò)誤代碼的文本描述代碼。如果未指定錯(cuò)誤代碼,則通過(guò)調(diào)用Windows api函數(shù)GetLastError來(lái)使用上一個(gè)錯(cuò)誤代碼。

    ctypes.GetLastError()

    僅限Windows:返回Windows在調(diào)用線(xiàn)程中設(shè)置的最后一個(gè)錯(cuò)誤代碼。此函數(shù)直接調(diào)用Windows GetLastError()函數(shù),它不返回錯(cuò)誤代碼的ctypes-private副本。

    ctypes.get_errno()

    返回errno調(diào)用線(xiàn)程中系統(tǒng)變量的ctypes-private副本的當(dāng)前值 。

    版本2.6中的新功能。

    ctypes.get_last_error()

    僅限Windows:返回LastError調(diào)用線(xiàn)程中系統(tǒng)變量的ctypes-private副本的當(dāng)前值 。

    版本2.6中的新功能。

    ctypes.memmovedstsrccount 

    與標(biāo)準(zhǔn)C memmove庫(kù)函數(shù)相同:將計(jì)數(shù)字節(jié)從 src復(fù)制到dstdstsrc必須是可以轉(zhuǎn)換為指針的整數(shù)或ctypes實(shí)例。

    ctypes.memsetdstccount 

    與標(biāo)準(zhǔn)C memset庫(kù)函數(shù)相同:使用值c的計(jì)數(shù)字節(jié)填充地址dst處的內(nèi)存塊。dst必須是指定地址的整數(shù)或ctypes實(shí)例。

    ctypes.POINTER類(lèi)型

    此工廠(chǎng)函數(shù)創(chuàng)建并返回新的ctypes指針類(lèi)型。指針類(lèi)型在內(nèi)部被緩存和重用,因此重復(fù)調(diào)用此函數(shù)很便宜。type必須是ctypes類(lèi)型。

    ctypes.pointerobj 

    此函數(shù)創(chuàng)建一個(gè)指向obj的新指針實(shí)例。返回的對(duì)象屬于該類(lèi)型POINTER(type(obj))

    注意:如果您只想將指向?qū)ο蟮闹羔槀鬟f給外部函數(shù)調(diào)用,則應(yīng)該使用byref(obj)哪個(gè)更快。

    ctypes.resizeobjsize 

    此函數(shù)調(diào)整obj的內(nèi)部?jī)?nèi)存緩沖區(qū)的大小,obj必須是ctypes類(lèi)型的實(shí)例。如下所示,不可能使緩沖區(qū)小于對(duì)象類(lèi)型的本機(jī)大小sizeof(type(obj)),但可以放大緩沖區(qū)。

    ctypes.set_conversion_mode編碼錯(cuò)誤

    此函數(shù)設(shè)置ctypes對(duì)象在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)用線(xiàn)程中系統(tǒng)變量的ctypes-private副本的當(dāng)前值設(shè)置為value并返回先前的值。

    版本2.6中的新功能。

    ctypes.set_last_error

    僅限Windows:將LastError調(diào)用線(xiàn)程中系統(tǒng)變量的ctypes-private副本的當(dāng)前值設(shè)置 為value并返回先前的值。

    版本2.6中的新功能。

    ctypes.sizeofobj_or_type 

    返回ctypes類(lèi)型或?qū)嵗齼?nèi)存緩沖區(qū)的大小(以字節(jié)為單位)。與C sizeof運(yùn)算符相同。

    ctypes.string_at地址[,大小] )

    這個(gè)函數(shù)返回了從內(nèi)存地址字符串地址。如果指定了size,則將其用作size,否則假定該字符串為零終止。

    ctypes.WinErrorcode = Nonedescr = None 

    僅限Windows:此函數(shù)可能是ctypes中最糟糕的名稱(chēng)。它創(chuàng)建了一個(gè)WindowsError實(shí)例。如果未指定代碼, GetLastError則調(diào)用以確定錯(cuò)誤代碼。如果descr未指定,FormatError()則調(diào)用以獲取錯(cuò)誤的文本描述。

    ctypes.wstring_at地址[,大小] )

    這個(gè)函數(shù)返回了從內(nèi)存地址寬字符串 地址為unicode字符串。如果指定了size,則將其用作字符串的字符數(shù),否則假定該字符串為零終止。

       15.17.2.6。數(shù)據(jù)類(lèi)型

    類(lèi)ctypes._CData

    這個(gè)非公共類(lèi)是所有ctypes數(shù)據(jù)類(lèi)型的公共基類(lèi)。除此之外,所有ctypes類(lèi)型實(shí)例都包含一個(gè)保存C兼容數(shù)據(jù)的內(nèi)存塊; addressof()輔助函數(shù)返回內(nèi)存塊的地址 。另一個(gè)實(shí)例變量暴露為 _objects; 這包含其他需要保持活動(dòng)的Python對(duì)象,以防內(nèi)存塊包含指針。

    ctypes數(shù)據(jù)類(lèi)型的常用方法,這些都是類(lèi)方法(確切地說(shuō),它們是元類(lèi)的方法):

    from_buffer來(lái)源[,偏移] )

    此方法返回共享對(duì)象的緩沖區(qū)的ctypes實(shí)例 。所述對(duì)象必須支持可寫(xiě)緩沖器接口。可選的offset參數(shù)指定源緩沖區(qū)的偏移量(以字節(jié)為單位); 默認(rèn)值為零。如果源緩沖區(qū)不夠大,ValueError則會(huì)引發(fā)a。

    版本2.6中的新功能。

    from_buffer_copy來(lái)源[,偏移] )

    此方法創(chuàng)建一個(gè)ctypes實(shí)例,從對(duì)象緩沖區(qū)復(fù)制緩沖區(qū),該 緩沖區(qū)必須是可讀的。可選的offset 參數(shù)指定源緩沖區(qū)的偏移量(以字節(jié)為單位); 默認(rèn)值為零。如果源緩沖區(qū)不夠大,ValueError則會(huì)引發(fā)a。

    版本2.6中的新功能。

    from_address地址

    此方法使用address指定的內(nèi)存返回ctypes類(lèi)型實(shí)例,該內(nèi)存 必須是整數(shù)。

    from_paramobj 

    此方法使obj適應(yīng)ctypes類(lèi)型。當(dāng)外部函數(shù)的argtypes元組中存在類(lèi)型時(shí),使用外部函數(shù)調(diào)用中使用的實(shí)際對(duì)象調(diào)用它; 它必須返回一個(gè)可以用作函數(shù)調(diào)用參數(shù)的對(duì)象。

    所有ctypes數(shù)據(jù)類(lèi)型都具有此類(lèi)方法的默認(rèn)實(shí)現(xiàn),如果是類(lèi)型的實(shí)例,則通常返回obj。某些類(lèi)型也接受其他對(duì)象。

    in_dll圖書(shū)館名稱(chēng)

    此方法返回由共享庫(kù)導(dǎo)出的ctypes類(lèi)型實(shí)例。name是導(dǎo)出數(shù)據(jù)的符號(hào)的名稱(chēng),library 是加載的共享庫(kù)。

    ctypes數(shù)據(jù)類(lèi)型的常見(jiàn)實(shí)例變量:

    _b_base_

    有時(shí)ctypes數(shù)據(jù)實(shí)例不擁有它們包含的內(nèi)存塊,而是共享基礎(chǔ)對(duì)象的部分內(nèi)存塊。所述 _b_base_只讀構(gòu)件是根ctypes的對(duì)象擁有該存儲(chǔ)器塊。

    _b_needsfree_

    當(dāng)ctypes數(shù)據(jù)實(shí)例已分配內(nèi)存塊本身時(shí),此只讀變量為true,否則為false。

    _objects

    該成員None或者是包含需要保持活動(dòng)的Python對(duì)象的字典,以便內(nèi)存塊內(nèi)容保持有效。該對(duì)象僅用于調(diào)試; 永遠(yuǎn)不要修改這本詞典的內(nèi)容。

       15.17.2.7。基本數(shù)據(jù)類(lèi)型

    類(lèi)ctypes._SimpleCData

    這個(gè)非公共類(lèi)是所有基本ctypes數(shù)據(jù)類(lèi)型的基類(lèi)。這里提到它是因?yàn)樗綾types數(shù)據(jù)類(lèi)型的公共屬性。 _SimpleCData是它的子類(lèi) _CData,因此它繼承了它們的方法和屬性。

    在版本2.6中更改:現(xiàn)在可以對(duì)不包含指針但不包含指針的ctypes數(shù)據(jù)類(lèi)型進(jìn)行pickle。

    實(shí)例具有單個(gè)屬性:

    value

    該屬性包含實(shí)例的實(shí)際值。對(duì)于整數(shù)和指針類(lèi)型,它是一個(gè)整數(shù),對(duì)于字符類(lèi)型,它是單個(gè)字符串,對(duì)于字符指針類(lèi)型,它是Python字符串或unicode字符串。

    當(dāng)value屬性從一個(gè)ctypes實(shí)例獲取,通常是一個(gè)新的對(duì)象,每次返回。 ctypes沒(méi)有實(shí)現(xiàn)原來(lái)的目標(biāo)回報(bào)率,總是一個(gè)新的對(duì)象被創(chuàng)建。所有其他ctypes對(duì)象實(shí)例也是如此。

    基本數(shù)據(jù)類(lèi)型作為外部函數(shù)調(diào)用結(jié)果返回時(shí),或者例如通過(guò)檢索結(jié)構(gòu)字段成員或數(shù)組項(xiàng),將透明地轉(zhuǎn)換為本機(jī)Python類(lèi)型。換句話(huà)說(shuō),如果一個(gè)外國(guó)函數(shù)有一個(gè) restypec_char_p,你總是會(huì)收到一個(gè)Python字符串, 不是一個(gè)c_char_p實(shí)例。

    基本數(shù)據(jù)類(lèi)型的子類(lèi)不會(huì)繼承此行為。因此,如果外部函數(shù)restype是其子類(lèi)c_void_p,您將從函數(shù)調(diào)用中接收此子類(lèi)的實(shí)例。當(dāng)然,您可以通過(guò)訪(fǎng)問(wèn)value屬性來(lái)獲取指針的值。

    這些是基本的ctypes數(shù)據(jù)類(lèi)型:

    類(lèi)ctypes.c_byte

    表示C 數(shù)據(jù)類(lèi)型,并將該值解釋為小整數(shù)。構(gòu)造函數(shù)接受可選的整數(shù)初始值設(shè)定項(xiàng); 沒(méi)有進(jìn)行溢出檢查。signed char

    類(lèi)ctypes.c_char

    表示C char數(shù)據(jù)類(lèi)型,并將該值解釋為單個(gè)字符。構(gòu)造函數(shù)接受可選的字符串初始值設(shè)定項(xiàng),字符串的長(zhǎng)度必須恰好是一個(gè)字符。

    類(lèi)ctypes.c_char_p

    當(dāng)它指向以零結(jié)尾的字符串時(shí)表示C 數(shù)據(jù)類(lèi)型。對(duì)于也可能指向二進(jìn)制數(shù)據(jù)的通用字符指針, 必須使用。構(gòu)造函數(shù)接受整數(shù)地址或字符串。char *POINTER(c_char)

    類(lèi)ctypes.c_double

    表示C double數(shù)據(jù)類(lèi)型。構(gòu)造函數(shù)接受可選的float初始化程序。

    類(lèi)ctypes.c_longdouble

    表示C 數(shù)據(jù)類(lèi)型。構(gòu)造函數(shù)接受可選的float初始化程序。在它是別名的平臺(tái)上。long doublesizeof(long double) == sizeof(double)c_double

    版本2.6中的新功能。

    類(lèi)ctypes.c_float

    表示C float數(shù)據(jù)類(lèi)型。構(gòu)造函數(shù)接受可選的float初始化程序。

    類(lèi)ctypes.c_int

    表示C 數(shù)據(jù)類(lèi)型。構(gòu)造函數(shù)接受可選的整數(shù)初始值設(shè)定項(xiàng); 沒(méi)有進(jìn)行溢出檢查。在它是別名的平臺(tái)上。signed intsizeof(int) == sizeof(long)c_long

    類(lèi)ctypes.c_int8

    表示C 8位數(shù)據(jù)類(lèi)型。通常是別名 。signed intc_byte

    類(lèi)ctypes.c_int16

    表示C 16位數(shù)據(jù)類(lèi)型。通常是別名 。signed intc_short

    類(lèi)ctypes.c_int32

    表示C 32位數(shù)據(jù)類(lèi)型。通常是別名 。signed intc_int

    類(lèi)ctypes.c_int64

    表示C 64位數(shù)據(jù)類(lèi)型。通常是別名 。signed intc_longlong

    類(lèi)ctypes.c_long

    表示C 數(shù)據(jù)類(lèi)型。構(gòu)造函數(shù)接受可選的整數(shù)初始值設(shè)定項(xiàng); 沒(méi)有進(jìn)行溢出檢查。signed long

    類(lèi)ctypes.c_longlong

    表示C 數(shù)據(jù)類(lèi)型。構(gòu)造函數(shù)接受可選的整數(shù)初始值設(shè)定項(xiàng); 沒(méi)有進(jìn)行溢出檢查。signed long long

    類(lèi)ctypes.c_short

    表示C 數(shù)據(jù)類(lèi)型。構(gòu)造函數(shù)接受可選的整數(shù)初始值設(shè)定項(xiàng); 沒(méi)有進(jìn)行溢出檢查。signed short

    類(lèi)ctypes.c_size_t

    表示C size_t數(shù)據(jù)類(lèi)型。

    類(lèi)ctypes.c_ssize_t

    表示C ssize_t數(shù)據(jù)類(lèi)型。

    版本2.7中的新功能。

    類(lèi)ctypes.c_ubyte

    表示C 數(shù)據(jù)類(lèi)型,它將值解釋為小整數(shù)。構(gòu)造函數(shù)接受可選的整數(shù)初始值設(shè)定項(xiàng); 沒(méi)有進(jìn)行溢出檢查。unsigned char

    類(lèi)ctypes.c_uint

    表示C 數(shù)據(jù)類(lèi)型。構(gòu)造函數(shù)接受可選的整數(shù)初始值設(shè)定項(xiàng); 沒(méi)有進(jìn)行溢出檢查。在它是別名的平臺(tái)上。unsigned intsizeof(int) == sizeof(long)c_ulong

    類(lèi)ctypes.c_uint8

    表示C 8位數(shù)據(jù)類(lèi)型。通常是別名 。unsigned intc_ubyte

    類(lèi)ctypes.c_uint16

    表示C 16位數(shù)據(jù)類(lèi)型。通常是別名 。unsigned intc_ushort

    類(lèi)ctypes.c_uint32

    表示C 32位數(shù)據(jù)類(lèi)型。通常是別名 。unsigned intc_uint

    類(lèi)ctypes.c_uint64

    表示C 64位數(shù)據(jù)類(lèi)型。通常是別名 。unsigned intc_ulonglong

    類(lèi)ctypes.c_ulong

    表示C 數(shù)據(jù)類(lèi)型。構(gòu)造函數(shù)接受可選的整數(shù)初始值設(shè)定項(xiàng); 沒(méi)有進(jìn)行溢出檢查。unsigned long

    類(lèi)ctypes.c_ulonglong

    表示C 數(shù)據(jù)類(lèi)型。構(gòu)造函數(shù)接受可選的整數(shù)初始值設(shè)定項(xiàng); 沒(méi)有進(jìn)行溢出檢查。unsigned long long

    類(lèi)ctypes.c_ushort

    表示C 數(shù)據(jù)類(lèi)型。構(gòu)造函數(shù)接受可選的整數(shù)初始值設(shè)定項(xiàng); 沒(méi)有進(jìn)行溢出檢查。unsigned short

    類(lèi)ctypes.c_void_p

    表示C 類(lèi)型。該值表示為整數(shù)。構(gòu)造函數(shù)接受可選的整數(shù)初始值設(shè)定項(xiàng)。void *

    類(lèi)ctypes.c_wchar

    表示C wchar_t數(shù)據(jù)類(lèi)型,并將該值解釋為單個(gè)字符的unicode字符串。構(gòu)造函數(shù)接受可選的字符串初始值設(shè)定項(xiàng),字符串的長(zhǎng)度必須恰好是一個(gè)字符。

    類(lèi)ctypes.c_wchar_p

    表示C 數(shù)據(jù)類(lèi)型,該數(shù)據(jù)類(lèi)型必須是指向以零結(jié)尾的寬字符串的指針。構(gòu)造函數(shù)接受整數(shù)地址或字符串。wchar_t *

    類(lèi)ctypes.c_bool

    表示C bool數(shù)據(jù)類(lèi)型(更準(zhǔn)確地說(shuō),_Bool來(lái)自C99)。它的值可以是True或者False,構(gòu)造函數(shù)接受任何具有真值的對(duì)象。

    版本2.6中的新功能。

    類(lèi)ctypes.HRESULT

    僅限Windows:表示一個(gè)HRESULT值,其中包含函數(shù)或方法調(diào)用的成功或錯(cuò)誤信息。

    類(lèi)ctypes.py_object

    表示C 數(shù)據(jù)類(lèi)型。在沒(méi)有參數(shù)的情況下調(diào)用它會(huì)創(chuàng)建一個(gè)指針。PyObject *NULL PyObject *

    ctypes.wintypes模塊提供了相當(dāng)長(zhǎng)的一段其他Windows特定的數(shù)據(jù)類(lèi)型,例如HWNDWPARAMDWORD。一些有用的結(jié)構(gòu),如MSGRECT定義。

       15.17.2.8。結(jié)構(gòu)化數(shù)據(jù)類(lèi)型

    class ctypes.Union* args** kw 

    原始字節(jié)順序的聯(lián)合的抽象基類(lèi)。

    class ctypes.BigEndianStructure* args** kw 

    大端字節(jié)順序結(jié)構(gòu)的抽象基類(lèi)。

    class ctypes.LittleEndianStructure* args** kw 

    小端字節(jié)順序結(jié)構(gòu)的抽象基類(lèi)。

    具有非本機(jī)字節(jié)順序的結(jié)構(gòu)不能包含指針類(lèi)型字段或包含指針類(lèi)型字段的任何其他數(shù)據(jù)類(lèi)型。

    class ctypes.Structure* args** kw 

    本機(jī)字節(jié)順序的結(jié)構(gòu)的抽象基類(lèi)。

    必須通過(guò)繼承其中一種類(lèi)型來(lái)創(chuàng)建具體結(jié)構(gòu)和聯(lián)合類(lèi)型,并至少定義一個(gè)_fields_類(lèi)變量。ctypes將創(chuàng)建描述符 s,允許通過(guò)直接屬性訪(fǎng)問(wèn)來(lái)讀取和寫(xiě)入字段。這些是

    _fields_

    定義結(jié)構(gòu)字段的序列。項(xiàng)目必須是2元組或3元組。第一項(xiàng)是字段的名稱(chēng),第二項(xiàng)指定字段的類(lèi)型; 它可以是任何ctypes數(shù)據(jù)類(lèi)型。

    對(duì)于整數(shù)類(lèi)型字段c_int,可以給出第三個(gè)可選項(xiàng)。它必須是一個(gè)小的正整數(shù),用于定義字段的位寬。

    字段名稱(chēng)在一個(gè)結(jié)構(gòu)或聯(lián)合中必須是唯一的。未選中此選項(xiàng),重復(fù)名稱(chēng)時(shí)只能訪(fǎng)問(wèn)一個(gè)字段。

    可以在定義Structure子類(lèi)的類(lèi)語(yǔ)句之后定義_fields_類(lèi)變量,這允許創(chuàng)建直接或間接引用自身的數(shù)據(jù)類(lèi)型:

    1. class List(Structure):
    2. pass
    3. List._fields_ = [("pnext", POINTER(List)),
    4. ...
    5. ]

    _fields_類(lèi)變量但是,必須被定義在第一次使用之前的類(lèi)型(創(chuàng)建一個(gè)實(shí)例,sizeof()被稱(chēng)為其上,等等)。稍后對(duì)_fields_類(lèi)變量的賦值將引發(fā)AttributeError。

    可以定義結(jié)構(gòu)類(lèi)型的子類(lèi),它們繼承基類(lèi)的字段以及_fields_子子類(lèi)中定義的字段(如果有的話(huà))。

    _pack_

    一個(gè)可選的小整數(shù),允許覆蓋實(shí)例中結(jié)構(gòu)字段的對(duì)齊方式。 _pack_必須在_fields_分配時(shí)定義,否則它將無(wú)效。

    _anonymous_

    一個(gè)可選序列,列出未命名(匿名)字段的名稱(chēng)。 _anonymous_必須在_fields_分配時(shí)定義,否則它將無(wú)效。

    此變量中列出的字段必須是結(jié)構(gòu)或聯(lián)合類(lèi)型字段。 ctypes將在結(jié)構(gòu)類(lèi)型中創(chuàng)建允許直接訪(fǎng)問(wèn)嵌套字段的描述符,而無(wú)需創(chuàng)建結(jié)構(gòu)或聯(lián)合字段。

    這是一個(gè)示例類(lèi)型(Windows):

    1. class _U(Union):
    2. _fields_ = [("lptdesc", POINTER(TYPEDESC)),
    3. ("lpadesc", POINTER(ARRAYDESC)),
    4. ("hreftype", HREFTYPE)]
    5. class TYPEDESC(Structure):
    6. _anonymous_ = ("u",)
    7. _fields_ = [("u", _U),
    8. ("vt", VARTYPE)]

    TYPEDESC結(jié)構(gòu)描述了COM數(shù)據(jù)類(lèi)型,該vt字段指定哪個(gè)聯(lián)合字段有效。由于該u字段被定義為匿名字段,因此現(xiàn)在可以直接從TYPEDESC實(shí)例訪(fǎng)問(wèn)成員。td.lptdesc并且td.u.lptdesc 是等價(jià)的,但前者更快,因?yàn)樗恍枰獎(jiǎng)?chuàng)建臨時(shí)聯(lián)合實(shí)例:

    1. td = TYPEDESC()
    2. td.vt = VT_PTR
    3. td.lptdesc = POINTER(some_type)
    4. td.u.lptdesc = POINTER(some_type)

    可以定義結(jié)構(gòu)的子類(lèi),它們繼承基類(lèi)的字段。如果子類(lèi)定義具有單獨(dú)的 _fields_變量,則在此指定的字段將附加到基類(lèi)的字段中。

    結(jié)構(gòu)和聯(lián)合構(gòu)造函數(shù)接受位置和關(guān)鍵字參數(shù)。位置參數(shù)用于按照出現(xiàn)的順序初始化成員字段_fields_。構(gòu)造函數(shù)中的關(guān)鍵字參數(shù)被解釋為屬性賦值,因此它們將_fields_使用相同的名稱(chēng)進(jìn)行初始化 ,或者為不存在的名稱(chēng)創(chuàng)建新屬性_fields_

       15.17.2.9。數(shù)組和指針

    class ctypes.Array* args 

    數(shù)組的抽象基類(lèi)。

    創(chuàng)建具體數(shù)組類(lèi)型的推薦方法是將任何ctypes數(shù)據(jù)類(lèi)型與正整數(shù)相乘 。或者,您可以繼承此類(lèi)型并定義_length__type_類(lèi)變量。可以使用標(biāo)準(zhǔn)下標(biāo)和切片訪(fǎng)問(wèn)來(lái)讀取和寫(xiě)入數(shù)組元素; 對(duì)于切片讀取,所得到的物體是 本身Array

    _length_

    一個(gè)正整數(shù),指定數(shù)組中元素的數(shù)量。超出范圍的下標(biāo)導(dǎo)致IndexError。將由返回len()

    _type_

    指定數(shù)組中每個(gè)元素的類(lèi)型。

    數(shù)組子類(lèi)構(gòu)造函數(shù)接受位置參數(shù),用于按順序初始化元素。

    類(lèi)ctypes._Pointer

    指針的私有抽象基類(lèi)。

    通過(guò)POINTER()使用將指向的類(lèi)型調(diào)用來(lái)創(chuàng)建具體指針類(lèi)型; 這是由自動(dòng)完成的 pointer()

    如果指針指向數(shù)組,則可以使用標(biāo)準(zhǔn)下標(biāo)和切片訪(fǎng)問(wèn)來(lái)讀取和寫(xiě)入其元素。指針對(duì)象沒(méi)有大小,因此len()會(huì)提高TypeError。否定下標(biāo)將在指針之前從內(nèi)存中讀取(如在C中),并且超出范圍的下標(biāo)可能會(huì)因訪(fǎng)問(wèn)沖突而崩潰(如果您很幸運(yùn))。

    _type_

    指定指向的類(lèi)型。

    contents

    返回指針指向的對(duì)象。分配給此屬性會(huì)將指針更改為指向指定的對(duì)象。

      本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶(hù)發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
      轉(zhuǎn)藏 分享 獻(xiàn)花(0

      0條評(píng)論

      發(fā)表

      請(qǐng)遵守用戶(hù) 評(píng)論公約

      類(lèi)似文章 更多

      主站蜘蛛池模板: 国产精品中文字幕一区| 日韩精品国产二区三区| 91福利视频一区二区| 欧美福利电影A在线播放| 久久WWW免费人成一看片| 在线视频中文字幕二区| 成人免费精品网站在线观看影片| 欧美午夜片欧美片在线观看| 亚洲旡码欧美大片| a级黑人大硬长爽猛出猛进| 亚洲欧美卡通另类丝袜美腿| 久久综合九色欧美综合狠狠| 国产精品亚洲二区在线播放| 精品久久久久久无码人妻热| 国产永久免费高清在线| 99草草国产熟女视频在线| 翘臀少妇被扒开屁股日出水爆乳| 男女扒开双腿猛进入爽爽免费看| 国产重口老太和小伙| 成人无码午夜在线观看| 色伦专区97中文字幕| 九九在线精品国产| 免费观看的AV毛片的网站| 国产裸体美女视频全黄| 中文字幕日韩国产精品| 久久天天躁狠狠躁夜夜AVAPP| 成人免费A级毛片无码片2022| 男女扒开双腿猛进入爽爽免费看| 日本高清无卡码一区二区| 精品国偷自产在线视频99| 影音先锋人妻啪啪AV资源网站| 夜鲁鲁鲁夜夜综合视频| 国产精品中文字幕观看| 亚洲欧美日韩精品久久亚洲区| 成年视频人免费网站动漫在线| 丁香五月亚洲综合在线国内自拍| 337P日本欧洲亚洲大胆精品| 丰满人妻AV无码一区二区三区| 国产高清在线男人的天堂| 亚洲av午夜成人片| 亚洲国产精品久久一线不卡|