ctypes
— A foreign function library for PythonPython的外部函数库¶
ctypes
is a foreign function library for Python. 是Python的外部函数库。It provides C compatible data types, and allows calling functions in DLLs or shared libraries. 它提供与C兼容的数据类型,并允许在DLL或共享库中调用函数。It can be used to wrap these libraries in pure Python.它可以用于在纯Python中包装这些库。
ctypes tutorialctypes教程¶
Note: The code samples in this tutorial use 注意:本教程中的代码示例使用doctest
to make sure that they actually work. doctest
来确保它们确实有效。Since some code samples behave differently under Linux, Windows, or macOS, they contain doctest directives in comments.由于一些代码示例在Linux、Windows或macOS下的行为不同,因此它们在注释中包含doctest指令。
Note: Some code samples reference the ctypes 注意:一些代码示例引用ctypes c_int
type. c_int
类型。On platforms where 在sizeof(long) == sizeof(int)
it is an alias to c_long
. sizeof(long) == sizeof(int)
的平台上,它是c_long
的别名。So, you should not be confused if 因此,如果您希望打印c_long
is printed if you would expect c_int
— they are actually the same type.c_int
,那么不应该混淆是否打印了c_long
-它们实际上是相同的类型。
Loading dynamic link libraries加载动态链接库¶
ctypes
exports the cdll, and on Windows windll and oledll objects, for loading dynamic link libraries.导出cdll,并在Windows windll和oledll对象上,用于加载动态链接库。
You load libraries by accessing them as attributes of these objects. 通过将库作为这些对象的属性进行访问来加载库。cdll loads libraries which export functions using the standard cdll加载使用标准cdecl
calling convention, while windll libraries call functions using the stdcall
calling convention. cdecl
调用约定导出函数的库,而windll库使用stdcall
调用约定调用函数。oledll also uses the oledll还使用stdcall
calling convention, and assumes the functions return a Windows HRESULT
error code. stdcall
调用约定,并假定函数返回Windows HRESULT
错误代码。The error code is used to automatically raise an 错误代码用于在函数调用失败时自动引发OSError
exception when the function call fails.OSError
异常。
Changed in version 3.3:版本3.3中更改: Windows errors used to raise Windows错误用于引发WindowsError
, which is now an alias of OSError
.WindowsError
,它现在是OSError
的别名。
Here are some examples for Windows. 下面是一些Windows示例。Note that 请注意,msvcrt
is the MS standard C library containing most standard C functions, and uses the cdecl calling convention:msvcrt
是包含大多数标准C函数的MS标准C库,并使用cdecl调用约定:
>>> from ctypes import *
>>> print(windll.kernel32)
<WinDLL 'kernel32', handle ... at ...>
>>> print(cdll.msvcrt)
<CDLL 'msvcrt', handle ... at ...>
>>> libc = cdll.msvcrt
>>>
Windows appends the usual Windows会自动附加通常的.dll
file suffix automatically..dll
文件后缀。
Note
Accessing the standard C library through 通过cdll.msvcrt
will use an outdated version of the library that may be incompatible with the one being used by Python. cdll.msvcrt
访问标准C库将使用库的过期版本,该版本可能与Python使用的版本不兼容。Where possible, use native Python functionality, or else import and use the 如果可能,请使用本机Python功能,或者导入并使用msvcrt
module.msvcrt
模块。
On Linux, it is required to specify the filename including the extension to load a library, so attribute access can not be used to load libraries. 在Linux上,需要指定文件名(包括加载库的扩展名),因此不能使用属性访问来加载库。Either the 要么使用dll加载器的LoadLibrary()
method of the dll loaders should be used, or you should load the library by creating an instance of CDLL by calling the constructor:LoadLibrary()
方法,要么通过调用构造函数创建CDLL实例来加载库:
>>> cdll.LoadLibrary("libc.so.6")
<CDLL 'libc.so.6', handle ... at ...>
>>> libc = CDLL("libc.so.6")
>>> libc
<CDLL 'libc.so.6', handle ... at ...>
>>>
Accessing functions from loaded dlls从加载的dll访问函数¶
Functions are accessed as attributes of dll objects:函数作为dll对象的属性进行访问:
>>> from ctypes import *
>>> libc.printf
<_FuncPtr object at 0x...>
>>> print(windll.kernel32.GetModuleHandleA)
<_FuncPtr object at 0x...>
>>> print(windll.kernel32.MyOwnFunction)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "ctypes.py", line 239, in __getattr__
func = _StdcallFuncPtr(name, self)
AttributeError: function 'MyOwnFunction' not found
>>>
Note that win32 system dlls like 注意,像kernel32
and user32
often export ANSI as well as UNICODE versions of a function. kernel32
和user32
这样的win32系统dll通常导出函数的ANSI和UNICODE版本。The UNICODE version is exported with an 导出UNICODE版本时,名称后面附加W
appended to the name, while the ANSI version is exported with an A
appended to the name. W
,而导出ANSI版本时,其名称后面附加A
。The win32 win32 GetModuleHandle
function, which returns a module handle for a given module name, has the following C prototype, and a macro is used to expose one of them as GetModuleHandle
depending on whether UNICODE is defined or not:GetModuleHandle
函数返回给定模块名称的模块句柄,该函数具有以下C原型,根据是否定义了UNICODE,使用宏将其中一个原型公开为GetModuleHandle:
/* ANSI version */
HMODULE GetModuleHandleA(LPCSTR lpModuleName);
/* UNICODE version */
HMODULE GetModuleHandleW(LPCWSTR lpModuleName);
windll does not try to select one of them by magic, you must access the version you need by specifying windll不会尝试通过魔法选择其中一个,您必须通过显式指定GetModuleHandleA
or GetModuleHandleW
explicitly, and then call it with bytes or string objects respectively.GetModuleHandleA
或GetModuleHandleW
来访问所需的版本,然后分别用字节或字符串对象调用它。
Sometimes, dlls export functions with names which aren’t valid Python identifiers, like 有时,dll会导出名称不是有效Python标识符的函数,如"??2@YAPAXI@Z"
. "??2@YAPAXI@Z"
。In this case you have to use 在这种情况下,您必须使用getattr()
to retrieve the function:getattr()
来检索函数:
>>> getattr(cdll.msvcrt, "??2@YAPAXI@Z")
<_FuncPtr object at 0x...>
>>>
On Windows, some dlls export functions not by name but by ordinal. 在Windows上,有些dll不是按名称而是按序号导出函数。These functions can be accessed by indexing the dll object with the ordinal number:可以通过使用序号索引dll对象来访问这些函数:
>>> cdll.kernel32[1]
<_FuncPtr object at 0x...>
>>> cdll.kernel32[0]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "ctypes.py", line 310, in __getitem__
func = _StdcallFuncPtr(name, self)
AttributeError: function ordinal 0 not found
>>>
Calling functions调用函数¶
You can call these functions like any other Python callable. 您可以像调用任何其他Python可调用函数一样调用这些函数。This example uses the 此示例使用time()
function, which returns system time in seconds since the Unix epoch, and the GetModuleHandleA()
function, which returns a win32 module handle.time()
函数,该函数返回Unix epoch之后的系统时间(以秒为单位),以及GetModuleHandleA()
函数(返回win32模块句柄)。
This example calls both functions with a 此示例使用NULL
pointer (None
should be used as the NULL
pointer):NULL
指针调用这两个函数(应将None
用作NULL
指针):
>>> print(libc.time(None))
1150640792
>>> print(hex(windll.kernel32.GetModuleHandleA(None)))
0x1d000000
>>>
使用ValueError
is raised when you call an stdcall
function with the cdecl
calling convention, or vice versa:cdecl
调用约定调用stdcall
函数时,会引发ValueError
,反之亦然:
>>> cdll.kernel32.GetModuleHandleA(None)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: Procedure probably called with not enough arguments (4 bytes missing)
>>>
>>> windll.msvcrt.printf(b"spam")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: Procedure probably called with too many arguments (4 bytes in excess)
>>>
To find out the correct calling convention you have to look into the C header file or the documentation for the function you want to call.要找到正确的调用约定,您必须查看C头文件或要调用的函数的文档。
On Windows, 在Windows上,当使用无效参数值调用函数时,ctypes
uses win32 structured exception handling to prevent crashes from general protection faults when functions are called with invalid argument values:ctypes
使用win32结构化异常处理来防止一般保护错误导致的崩溃:
>>> windll.kernel32.GetModuleHandleA(32)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
OSError: exception: access violation reading 0x00000020
>>>
There are, however, enough ways to crash Python with 然而,有足够的方法可以用ctypes
, so you should be careful anyway. ctypes
,使Python崩溃,所以无论如何都应该小心。The faulthandler
module can be helpful in debugging crashes (e.g. from segmentation faults produced by erroneous C library calls).faulthandler
模块有助于调试崩溃(例如,错误的C库调用产生的分段错误)。
None
, integers, bytes objects and (unicode) strings are the only native Python objects that can directly be used as parameters in these function calls. 、整数、字节对象和(unicode)字符串是唯一可以在这些函数调用中直接用作参数的本地Python对象。None
is passed as a C NULL
pointer, bytes objects and strings are passed as pointer to the memory block that contains their data (char* or wchar_t*). None
作为C NULL
指针传递,bytes对象和字符串作为指向包含其数据的内存块(char*或wchar_t*)的指针传递。Python integers are passed as the platforms default C int type, their value is masked to fit into the C type.Python整数作为平台默认的C int类型传递,它们的值被屏蔽以适应C类型。
Before we move on calling functions with other parameter types, we have to learn more about 在继续使用其他参数类型调用函数之前,我们必须了解更多关于ctypes
data types.ctypes
数据类型的信息。
Fundamental data types基本数据类型¶
ctypes
defines a number of primitive C compatible data types:定义了许多与C兼容的基元数据类型:
ctypes type |
C type |
Python type |
---|---|---|
_Bool |
bool (1) |
|
char |
1-character bytes object |
|
|
1-character string |
|
char |
int |
|
unsigned char |
int |
|
short |
int |
|
unsigned short |
int |
|
int |
int |
|
unsigned int |
int |
|
long |
int |
|
unsigned long |
int |
|
|
int |
|
unsigned __int64 or unsigned long long |
int |
|
|
int |
|
|
int |
|
float |
float |
|
double |
float |
|
long double |
float |
|
char* (NUL terminated) |
bytes object or |
|
wchar_t* (NUL terminated) |
string or |
|
void* |
int or |
The constructor accepts any object with a truth value.构造函数接受具有真值的任何对象。
All these types can be created by calling them with an optional initializer of the correct type and value:所有这些类型都可以通过使用正确类型和值的可选初始值设定项来调用它们来创建:
>>> c_int()
c_long(0)
>>> c_wchar_p("Hello, World")
c_wchar_p(140018365411392)
>>> c_ushort(-3)
c_ushort(65533)
>>>
Since these types are mutable, their value can also be changed afterwards:由于这些类型是可变的,因此它们的值也可以在以后更改:
>>> i = c_int(42)
>>> print(i)
c_long(42)
>>> print(i.value)
42
>>> i.value = -99
>>> print(i.value)
-99
>>>
Assigning a new value to instances of the pointer types c_char_p
, c_wchar_p
, and c_void_p
changes the memory location they point to, not the contents of the memory block (of course not, because Python bytes objects are immutable):
>>> s = "Hello, World"
>>> c_s = c_wchar_p(s)
>>> print(c_s)
c_wchar_p(139966785747344)
>>> print(c_s.value)
Hello World
>>> c_s.value = "Hi, there"
>>> print(c_s) # the memory location has changed
c_wchar_p(139966783348904)
>>> print(c_s.value)
Hi, there
>>> print(s) # first object is unchanged
Hello, World
>>>
You should be careful, however, not to pass them to functions expecting pointers to mutable memory. 但是,您应该小心,不要将它们传递给需要指向可变内存的指针的函数。If you need mutable memory blocks, ctypes has a 如果需要可变内存块,ctypes有一个create_string_buffer()
function which creates these in various ways. create_string_buffer()
函数,可以用各种方式创建这些内存块。The current memory block contents can be accessed (or changed) with the 可以使用raw
property; if you want to access it as NUL terminated string, use the value
property:raw
属性访问(或更改)当前内存块内容;如果要将其作为以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 b'\x00\x00\x00'
>>> p = create_string_buffer(b"Hello") # create a buffer containing a NUL terminated string
>>> print(sizeof(p), repr(p.raw))
6 b'Hello\x00'
>>> print(repr(p.value))
b'Hello'
>>> p = create_string_buffer(b"Hello", 10) # create a 10 byte buffer
>>> print(sizeof(p), repr(p.raw))
10 b'Hello\x00\x00\x00\x00\x00'
>>> p.value = b"Hi"
>>> print(sizeof(p), repr(p.raw))
10 b'Hi\x00lo\x00\x00\x00\x00\x00'
>>>
The create_string_buffer()
function replaces the c_buffer()
function (which is still available as an alias), as well as the c_string()
function from earlier ctypes releases. create_string_buffer()
函数替换了c_buffers()
函数(它仍然作为别名可用),以及早期ctypes发行版中的c_string()
函数。To create a mutable memory block containing unicode characters of the C type 要创建包含C类型wchar_t
use the create_unicode_buffer()
function.wchar_t
的unicode字符的可变内存块,请使用create_unicode_buffer()
函数。
Calling functions, continued调用函数(续)¶
Note that printf prints to the real standard output channel, not to 请注意,printf打印到真正的标准输出通道,而不是sys.stdout
, so these examples will only work at the console prompt, not from within IDLE or PythonWin:sys.stdout
,因此这些示例只能在控制台提示符下起作用,而不能在IDLE或PythonWin中起作用:
>>> printf = libc.printf
>>> printf(b"Hello, %s\n", b"World!")
Hello, World!
14
>>> printf(b"Hello, %S\n", "World!")
Hello, World!
14
>>> printf(b"%d bottles of beer\n", 42)
42 bottles of beer
19
>>> printf(b"%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
>>>
As has been mentioned before, all Python types except integers, strings, and bytes objects have to be wrapped in their corresponding 如前所述,除整数、字符串和字节对象之外的所有Python类型都必须包装在相应的ctypes
type, so that they can be converted to the required C data type:ctypes
类型中,以便转换为所需的C数据类型:
>>> printf(b"An int %d, a double %f\n", 1234, c_double(3.14))
An int 1234, a double 3.140000
31
>>>
Calling functions with your own custom data types使用您自己的自定义数据类型调用函数¶
You can also customize 您还可以自定义ctypes
argument conversion to allow instances of your own classes be used as function arguments. ctypes
参数转换,以允许您自己的类的实例用作函数参数。ctypes
looks for an _as_parameter_
attribute and uses this as the function argument. ctypes
查找_as_parameter_
属性并将其用作函数参数。Of course, it must be one of integer, string, or bytes:当然,它必须是整数、字符串或字节之一:
>>> class Bottles:
... def __init__(self, number):
... self._as_parameter_ = number
...
>>> bottles = Bottles(42)
>>> printf(b"%d bottles of beer\n", bottles)
42 bottles of beer
19
>>>
If you don’t want to store the instance’s data in the 如果不想将实例的数据存储在_as_parameter_实例变量中,可以定义一个_as_parameter_
instance variable, you could define a property
which makes the attribute available on request.property
,使该属性在请求时可用。
Specifying the required argument types (function prototypes)指定所需的参数类型(函数原型)¶
It is possible to specify the required argument types of functions exported from DLLs by setting the 通过设置argtypes
attribute.argtypes
属性,可以指定从DLL导出的函数所需的参数类型。
argtypes
must be a sequence of C data types (the 必须是一系列C数据类型(printf
function is probably not a good example here, because it takes a variable number and different types of parameters depending on the format string, on the other hand this is quite handy to experiment with this feature):printf
函数在这里可能不是一个好例子,因为它需要一个可变的数字和不同类型的参数,这取决于格式字符串,另一方面,这对于试验此功能非常方便):
>>> printf.argtypes = [c_char_p, c_char_p, c_int, c_double]
>>> printf(b"String '%s', Int %d, Double %f\n", b"Hi", 10, 2.2)
String 'Hi', Int 10, Double 2.200000
37
>>>
Specifying a format protects against incompatible argument types (just as a prototype for a C function), and tries to convert the arguments to valid types:指定格式可以防止不兼容的参数类型(就像C函数的原型一样),并尝试将参数转换为有效类型:
>>> printf(b"%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(b"%s %d %f\n", b"X", 2, 3)
X 2 3.000000
13
>>>
If you have defined your own classes which you pass to function calls, you have to implement a 如果定义了传递给函数调用的自己的类,则必须实现from_param()
class method for them to be able to use them in the argtypes
sequence. from_param()
类方法,以便它们能够在argtypes
序列中使用它们。The from_param()
class method receives the Python object passed to the function call, it should do a typecheck or whatever is needed to make sure this object is acceptable, and then return the object itself, its _as_parameter_
attribute, or whatever you want to pass as the C function argument in this case. from_param()
类方法接收传递给函数调用的Python对象,它应该进行类型检查或任何必要的操作,以确保该对象是可接受的,然后返回对象本身、其_as_parameter_
属性,或者在本例中作为C函数参数传递的任何内容。Again, the result should be an integer, string, bytes, a 同样,结果应该是整数、字符串、字节、ctypes
instance, or an object with an _as_parameter_
attribute.ctypes
实例或具有_as_parameter_
属性的对象。
Return types返回类型¶
By default functions are assumed to return the C int type. 默认情况下,假设函数返回C int类型。Other return types can be specified by setting the 可以通过设置函数对象的restype
attribute of the function object.restype
属性来指定其他返回类型。
Here is a more advanced example, it uses the 下面是一个更高级的示例,它使用strchr
function, which expects a string pointer and a char, and returns a pointer to a string:strchr
函数,该函数需要一个字符串指针和一个字符,并返回一个指向字符串的指针:
>>> strchr = libc.strchr
>>> strchr(b"abcdef", ord("d"))
8059983
>>> strchr.restype = c_char_p # c_char_p is a pointer to a string
>>> strchr(b"abcdef", ord("d"))
b'def'
>>> print(strchr(b"abcdef", ord("x")))
None
>>>
If you want to avoid the 如果要避免上述ord("x")
calls above, you can set the argtypes
attribute, and the second argument will be converted from a single character Python bytes object into a C char:ord("x")
调用,可以设置argtypes
属性,第二个参数将从单个字符的Python字节对象转换为C字符:
>>> strchr.restype = c_char_p
>>> strchr.argtypes = [c_char_p, c_char]
>>> strchr(b"abcdef", b"d")
'def'
>>> strchr(b"abcdef", b"def")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ArgumentError: argument 2: exceptions.TypeError: one character string expected
>>> print(strchr(b"abcdef", b"x"))
None
>>> strchr(b"abcdef", b"d")
'def'
>>>
You can also use a callable Python object (a function or a class for example) as the 如果外部函数返回整数,还可以使用可调用的Python对象(例如函数或类)作为restype
attribute, if the foreign function returns an integer. restype
属性。The callable will be called with the integer the C function returns, and the result of this call will be used as the result of your function call. 将使用C函数返回的integer调用可调用函数,此调用的结果将用作函数调用的结果。This is useful to check for error return values and automatically raise an exception:这有助于检查错误返回值并自动引发异常:
>>> 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
OSError: [Errno 126] The specified module could not be found.
>>>
WinError
is a function which will call Windows 是一个函数,它将调用Windows FormatMessage()
api to get the string representation of an error code, and returns an exception. FormatMessage()
api来获取错误代码的字符串表示形式,并返回异常。WinError
takes an optional error code parameter, if no one is used, it calls GetLastError()
to retrieve it.WinError
接受一个可选的错误代码参数,如果没有使用该参数,它将调用GetLastError()
来检索它。
Please note that a much more powerful error checking mechanism is available through the 请注意,通过errcheck
attribute; see the reference manual for details.errcheck
属性可以使用更强大的错误检查机制;有关详细信息,请参阅参考手册。
Passing pointers (or: passing parameters by reference)传递指针(或:通过引用传递参数)¶
Sometimes a C api function expects a pointer to a data type as parameter, probably to write into the corresponding location, or if the data is too large to be passed by value. 有时,C api函数需要一个指向数据类型的指针作为参数,可能会写入相应的位置,或者数据太大而无法通过值传递。This is also known as passing parameters by reference.这也称为通过引用传递参数。
ctypes
exports the 导出用于通过引用传递参数的byref()
function which is used to pass parameters by reference. byref()
函数。The same effect can be achieved with the 使用pointer()
function, although pointer()
does a lot more work since it constructs a real pointer object, so it is faster to use byref()
if you don’t need the pointer object in Python itself:pointer()
函数也可以达到同样的效果,尽管pointer()
起了很大的作用,因为它构造了一个真实的指针对象,所以使用byref()
能更快,如果你不需要Python自身的指针对象的话。
>>> i = c_int()
>>> f = c_float()
>>> s = create_string_buffer(b'\000' * 32)
>>> print(i.value, f.value, repr(s.value))
0 0.0 b''
>>> libc.sscanf(b"1 3.14 Hello", b"%d %f %s",
... byref(i), byref(f), s)
3
>>> print(i.value, f.value, repr(s.value))
1 3.1400001049 b'Hello'
>>>
Structures and unions结构和接头¶
Structures and unions must derive from the Structure
and Union
base classes which are defined in the ctypes
module. Structure
和Union
必须派生自ctypes
模块中定义的Structure和Union基类。Each subclass must define a 每个子类都必须定义_fields_
attribute. _fields_
属性。_fields_
must be a list of 2-tuples, containing a field name and a field type.必须是包含字段名和字段类型的两元组列表。
The field type must be a 字段类型必须是类似于ctypes
type like c_int
, or any other derived ctypes
type: structure, union, array, pointer.c_int
的ctypes
类型,或任何其他派生的ctypes
类型:structure、union、array、pointer。
Here is a simple example of a POINT structure, which contains two integers named x and y, and also shows how to initialize a structure in the constructor:下面是POINT结构的一个简单示例,它包含两个名为x和y的整数,还显示了如何在构造函数中初始化结构:
>>> 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>
TypeError: too many initializers
>>>
You can, however, build much more complicated structures. 然而,您可以构建更复杂的结构。A structure can itself contain other structures by using a structure as a field type.通过将结构用作字段类型,结构本身可以包含其他结构。
Here is a RECT structure which contains two POINTs named upperleft and lowerright:下面是一个RECT结构,它包含两个名为upperleft和lowerright:
>>> 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
>>>
Nested structures can also be initialized in the constructor in several ways:嵌套结构也可以通过以下几种方式在构造函数中初始化:
>>> r = RECT(POINT(1, 2), POINT(3, 4))
>>> r = RECT((1, 2), (3, 4))
Field descriptors can be retrieved from the class, they are useful for debugging because they can provide useful information:字段描述符可以从类中检索,它们对于调试很有用,因为它们可以提供有用的信息:
>>> print(POINT.x)
<Field type=c_long, ofs=0, size=4>
>>> print(POINT.y)
<Field type=c_long, ofs=4, size=4>
>>>
Warning
ctypes
does not support passing unions or structures with bit-fields to functions by value. 不支持按值将具有位字段的联合或结构传递给函数。While this may work on 32-bit x86, it’s not guaranteed by the library to work in the general case. 虽然这可以在32位x86上工作,但库不能保证在一般情况下工作。Unions and structures with bit-fields should always be passed to functions by pointer.具有位字段的联合和结构应始终通过指针传递给函数。
Structure/union alignment and byte order结构/联合对齐和字节顺序¶
By default, Structure and Union fields are aligned in the same way the C compiler does it. 默认情况下,Structure和Union字段的对齐方式与C编译器的对齐方式相同。It is possible to override this behavior by specifying a 可以通过在子类定义中指定_pack_
class attribute in the subclass definition. _pack_
类属性来覆盖此行为。This must be set to a positive integer and specifies the maximum alignment for the fields. 这必须设置为正整数,并指定字段的最大对齐方式。This is what 这就是#pragma pack(n)
also does in MSVC.#pragma pack(n)
在MSVC中的作用。
ctypes
uses the native byte order for Structures and Unions. 对结构和联合使用本机字节顺序。To build structures with non-native byte order, you can use one of the 要构建具有非本机字节顺序的结构,可以使用BigEndianStructure
, LittleEndianStructure
, BigEndianUnion
, and LittleEndianUnion
base classes. BigEndianStructure
、LittleEndianStructure
、BigEndianUnion
和LittleEndianUnion
基类之一。These classes cannot contain pointer fields.这些类不能包含指针字段。
Bit fields in structures and unions结构和联合中的位字段¶
It is possible to create structures and unions containing bit fields. 可以创建包含位字段的结构和联合。Bit fields are only possible for integer fields, the bit width is specified as the third item in the 位字段只能用于整数字段,位宽度指定为_fields_
tuples:_fields_
元组中的第三项:
>>> 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>
>>>
Arrays数组¶
Arrays are sequences, containing a fixed number of instances of the same type.数组是序列,包含固定数量的相同类型的实例。
The recommended way to create array types is by multiplying a data type with a positive integer:创建数组类型的建议方法是将数据类型与正整数相乘:
TenPointsArrayType = POINT * 10
Here is an example of a somewhat artificial data type, a structure containing 4 POINTs among other stuff:下面是一个有点人为的数据类型的示例,该结构包含4个POINT以及其他内容:
>>> 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
>>>
Instances are created in the usual way, by calling the class:实例是以通常的方式创建的,方法是调用类:
arr = TenPointsArrayType()
for pt in arr:
print(pt.x, pt.y)
The above code print a series of 上面的代码打印了一系列0 0
lines, because the array contents is initialized to zeros.0 0
行,因为数组内容被初始化为零。
Initializers of the correct type can also be specified:还可以指定正确类型的初始值设定项:
>>> 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, end=" ")
...
1 2 3 4 5 6 7 8 9 10
>>>
Pointers指针¶
Pointer instances are created by calling the 指针实例是通过对pointer()
function on a ctypes
type:ctypes
类型调用pointer()
函数创建的:
>>> from ctypes import *
>>> i = c_int(42)
>>> pi = pointer(i)
>>>
Pointer instances have a 指针实例有一个contents
attribute which returns the object to which the pointer points, the i
object above:contents
属性,它返回指针指向的对象,即上面的i
对象:
>>> pi.contents
c_long(42)
>>>
Note that 请注意,ctypes
does not have OOR (original object return), it constructs a new, equivalent object each time you retrieve an attribute:ctypes
没有OOR(原始对象返回),每次检索属性时,它都会构造一个新的等效对象:
>>> pi.contents is i
False
>>> pi.contents is pi.contents
False
>>>
Assigning another 将另一个c_int
instance to the pointer’s contents attribute would cause the pointer to point to the memory location where this is stored:c_int
实例指定给指针的contents属性将导致指针指向存储该实例的内存位置:
>>> i = c_int(99)
>>> pi.contents = i
>>> pi.contents
c_long(99)
>>>
Pointer instances can also be indexed with integers:指针实例也可以用整数进行索引:
>>> pi[0]
99
>>>
Assigning to an integer index changes the pointed to value:分配给整数索引会更改指向的值:
>>> print(i)
c_long(99)
>>> pi[0] = 22
>>> print(i)
c_long(22)
>>>
It is also possible to use indexes different from 0, but you must know what you’re doing, just as in C: You can access or change arbitrary memory locations. 也可以使用不同于0的索引,但您必须知道自己在做什么,就像在C中一样:您可以访问或更改任意内存位置。Generally you only use this feature if you receive a pointer from a C function, and you know that the pointer actually points to an array instead of a single item.通常,只有当您从C函数接收到一个指针,并且您知道该指针实际上指向一个数组而不是单个项时,才使用此功能。
Behind the scenes, the 在幕后,pointer()
function does more than simply create pointer instances, it has to create pointer types first. pointer()
函数不仅仅是创建指针实例,它还必须首先创建指针类型。This is done with the 这是通过POINTER()
function, which accepts any ctypes
type, and returns a new type:POINTER()
函数完成的,该函数接受任何ctypes
类型,并返回一个新类型:
>>> 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...>
>>>
Calling the pointer type without an argument creates a 不带参数调用指针类型将创建NULL
pointer. NULL
指针。NULL
pointers have a False
boolean value:NULL
指针具有False
布尔值:
>>> null_ptr = POINTER(c_int)()
>>> print(bool(null_ptr))
False
>>>
ctypes
checks for 在取消引用指针时检查NULL
when dereferencing pointers (but dereferencing invalid non-NULL
pointers would crash Python):NULL
(但取消引用无效的非NULL
指针会使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
>>>
Type conversions类型转换¶
Usually, ctypes does strict type checking. 通常,ctypes执行严格的类型检查。This means, if you have 这意味着,如果在函数的POINTER(c_int)
in the argtypes
list of a function or as the type of a member field in a structure definition, only instances of exactly the same type are accepted. argtypes
列表中有POINTER(c_int)
,或者作为结构定义中成员字段的类型,则只接受完全相同类型的实例。There are some exceptions to this rule, where ctypes accepts other objects. 这个规则有一些例外,ctypes接受其他对象。For example, you can pass compatible array instances instead of pointer types. 例如,可以传递兼容的数组实例,而不是指针类型。So, for 因此,对于POINTER(c_int)
, ctypes accepts an array of c_int:POINTER(c_int)
,ctypes接受c_int数组:
>>> 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
>>>
In addition, if a function argument is explicitly declared to be a pointer type (such as 此外,如果函数参数在POINTER(c_int)
) in argtypes
, an object of the pointed type (c_int
in this case) can be passed to the function. argtypes
中显式声明为指针类型(例如POINTER(c_int)
),则可以向函数传递一个指针类型的对象(在本例中为c_int
)。ctypes will apply the required 在这种情况下,ctypes将自动应用所需的byref()
conversion in this case automatically.byref()
转换。
To set a POINTER type field to 要将POINTER类型字段设置为NULL
, you can assign None
:NULL
,可以指定None
:
>>> bar.values = None
>>>
Sometimes you have instances of incompatible types. 有时您有不兼容类型的实例。In C, you can cast one type into another type. 在C语言中,可以将一种类型转换为另一种类型。ctypes
provides a cast()
function which can be used in the same way. ctypes
提供了一个cast()
函数,可以以同样的方式使用。The 上面定义的Bar
structure defined above accepts POINTER(c_int)
pointers or c_int
arrays for its values
field, but not instances of other types:Bar
结构接受POINTER(c_int)
指针或c_int
数组作为其values
字段,但不接受其他类型的实例:
>>> 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
>>>
For these cases, the 对于这些情况,cast()
function is handy.cast()
函数很方便。
The cast()
function can be used to cast a ctypes instance into a pointer to a different ctypes data type. cast()
函数可用于将ctypes实例转换为指向不同ctypes数据类型的指针。cast()
takes two parameters, a ctypes object that is or can be converted to a pointer of some kind, and a ctypes pointer type. 接受两个参数,一个是或可以转换为某种类型的指针的ctypes对象,另一个是ctypes指针类型。It returns an instance of the second argument, which references the same memory block as the first argument:它返回第二个参数的实例,该实例引用与第一个参数相同的内存块:
>>> a = (c_byte * 4)()
>>> cast(a, POINTER(c_int))
<ctypes.LP_c_long object at ...>
>>>
So, 因此,可以使用cast()
can be used to assign to the values
field of Bar
the structure:cast()
将结构分配给Bar
的values
字段:
>>> bar = Bar()
>>> bar.values = cast((c_byte * 4)(), POINTER(c_int))
>>> print(bar.values[0])
0
>>>
Incomplete Types不完整的类型¶
Incomplete Types are structures, unions or arrays whose members are not yet specified. 不完整类型是尚未指定其成员的结构、联合或数组。In C, they are specified by forward declarations, which are defined later:在C语言中,它们由forward声明指定,后者稍后定义:
struct cell; /* forward declaration */
struct cell {
char *name;
struct cell *next;
};
The straightforward translation into ctypes code would be this, but it does not work:直接转换为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
>>>
because the new 因为新的class cell
is not available in the class statement itself. class cell
在类语句本身中不可用。In 在ctypes
, we can define the cell
class and set the _fields_
attribute later, after the class statement:ctypes
中,我们可以在类语句之后定义cell
类并设置_fields_
属性:
>>> from ctypes import *
>>> class cell(Structure):
... pass
...
>>> cell._fields_ = [("name", c_char_p),
... ("next", POINTER(cell))]
>>>
Let’s try it. 让我们试试看。We create two instances of 我们创建了两个cell
, and let them point to each other, and finally follow the pointer chain a few times:cell
实例,让它们相互指向,最后沿着指针链几次:
>>> c1 = cell()
>>> c1.name = b"foo"
>>> c2 = cell()
>>> c2.name = b"bar"
>>> c1.next = pointer(c2)
>>> c2.next = pointer(c1)
>>> p = c1
>>> for i in range(8):
... print(p.name, end=" ")
... p = p.next[0]
...
foo bar foo bar foo bar foo bar
>>>
Callback functions回调函数¶
ctypes
allows creating C callable function pointers from Python callables. 允许从Python可调用函数创建C可调用函数指针。These are sometimes called callback functions.这些有时称为回调函数。
First, you must create a class for the callback function. 首先,必须为回调函数创建一个类。The class knows the calling convention, the return type, and the number and types of arguments this function will receive.该类知道调用约定、返回类型以及此函数将接收的参数的数量和类型。
The CFUNCTYPE()
factory function creates types for callback functions using the cdecl
calling convention. CFUNCTYPE()
工厂函数使用cdecl
调用约定为回调函数创建类型。On Windows, the 在Windows上,WINFUNCTYPE()
factory function creates types for callback functions using the stdcall
calling convention.WINFUNCTYPE()
工厂函数使用stdcall
调用约定为回调函数创建类型。
Both of these factory functions are called with the result type as first argument, and the callback functions expected argument types as the remaining arguments.调用这两个工厂函数时,将结果类型作为第一个参数,回调函数将参数类型作为剩余参数。
I will present an example here which uses the standard C library’s 我将在这里展示一个使用标准C库的qsort()
function, that is used to sort items with the help of a callback function. qsort()
函数的示例,该函数用于在回调函数的帮助下对项目进行排序。qsort()
will be used to sort an array of integers:qsort()
将用于对整数数组进行排序:
>>> IntArray5 = c_int * 5
>>> ia = IntArray5(5, 1, 7, 33, 99)
>>> qsort = libc.qsort
>>> qsort.restype = None
>>>
qsort()
must be called with a pointer to the data to sort, the number of items in the data array, the size of one item, and a pointer to the comparison function, the callback. 必须使用指向要排序的数据的指针、数据数组中的项目数、一个项目的大小以及指向比较函数回调的指针来调用。The callback will then be called with two pointers to items, and it must return a negative integer if the first item is smaller than the second, a zero if they are equal, and a positive integer otherwise.然后将使用两个指向项的指针调用回调,如果第一个项小于第二个项,回调必须返回一个负整数,如果它们相等,则返回一个零,否则返回一个正整数。
So our callback function receives pointers to integers, and must return an integer. 因此,回调函数接收指向整数的指针,并且必须返回整数。First we create the 首先,我们为回调函数创建type
for the callback function:type
:
>>> CMPFUNC = CFUNCTYPE(c_int, POINTER(c_int), POINTER(c_int))
>>>
To get started, here is a simple callback that shows the values it gets passed:首先,下面是一个简单的回调,它显示了传递的值:
>>> def py_cmp_func(a, b):
... print("py_cmp_func", a[0], b[0])
... return 0
...
>>> cmp_func = CMPFUNC(py_cmp_func)
>>>
The result:结果是:
>>> 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
>>>
Now we can actually compare the two items and return a useful result:现在我们可以实际比较这两个项目并返回一个有用的结果:
>>> def py_cmp_func(a, b):
... print("py_cmp_func", a[0], b[0])
... return a[0] - b[0]
...
>>>
>>> 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
>>>
As we can easily check, our array is sorted now:正如我们可以轻松检查的那样,数组现在已经排序:
>>> for i in ia: print(i, end=" ")
...
1 5 7 33 99
>>>
The function factories can be used as decorator factories, so we may as well write:函数工厂可以用作装饰工厂,因此我们不妨写下:
>>> @CFUNCTYPE(c_int, POINTER(c_int), POINTER(c_int))
... def py_cmp_func(a, b):
... print("py_cmp_func", a[0], b[0])
... return a[0] - b[0]
...
>>> qsort(ia, len(ia), sizeof(c_int), 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
>>>
Note
Make sure you keep references to 确保保留对CFUNCTYPE()
objects as long as they are used from C code. CFUNCTYPE()
对象的引用,只要它们是从C代码中使用的。ctypes
doesn’t, and if you don’t, they may be garbage collected, crashing your program when a callback is made.如果不这样做,它们可能会被垃圾收集,在回调时会导致程序崩溃。
Also, note that if the callback function is called in a thread created outside of Python’s control (e.g. by the foreign code that calls the callback), ctypes creates a new dummy Python thread on every invocation. 另外,请注意,如果在Python控制之外创建的线程中调用回调函数(例如,由调用回调的外部代码),则ctypes会在每次调用时创建一个新的伪Python-线程。This behavior is correct for most purposes, but it means that values stored with 这种行为在大多数情况下都是正确的,但这意味着用threading.local
will not survive across different callbacks, even when those calls are made from the same C thread.threading.local
存储的值在不同的回调中无法存活,即使这些调用是从同一个C线程进行的。
Accessing values exported from dlls访问从dll导出的值¶
Some shared libraries not only export functions, they also export variables. 一些共享库不仅导出函数,还导出变量。An example in the Python library itself is the Python库本身的一个例子是Py_OptimizeFlag
, an integer set to 0, 1, or 2, depending on the -O
or -OO
flag given on startup.Py_OptimizeFlag
,它是一个设置为0、1或2的整数,具体取决于启动时给定的-O
或-OO
标志。
ctypes
can access values like this with the 可以使用该类型的in_dll()
class methods of the type. indll()
类方法访问类似的值。pythonapi is a predefined symbol giving access to the Python C api:是一个预定义符号,用于访问Python C api:
>>> opt_flag = c_int.in_dll(pythonapi, "Py_OptimizeFlag")
>>> print(opt_flag)
c_long(0)
>>>
If the interpreter would have been started with 如果解释器是用-O
, the sample would have printed c_long(1)
, or c_long(2)
if -OO
would have been specified.-O
启动的,那么示例将打印c_long(1)
,如果指定了-OO
,则打印c_leng(2)
。
An extended example which also demonstrates the use of pointers accesses the 一个扩展示例还演示了指针的使用,它访问Python导出的PyImport_FrozenModules
pointer exported by Python.PyImport_FrozenModules
指针。
Quoting the docs for that value:为该值引用文档:
This pointer is initialized to point to an array of struct _frozen records, terminated by one whose members are all该指针被初始化为指向struct _frozen记录数组,由其成员全部为NULL
or zero.NULL
或零的数组终止。When a frozen module is imported, it is searched in this table.导入冻结模块时,将在此表中搜索该模块。Third-party code could play tricks with this to provide a dynamically created collection of frozen modules.第三方代码可以利用这一点来提供动态创建的冻结模块集合。
So manipulating this pointer could even prove useful. 因此,操纵这个指针甚至可以证明是有用的。To restrict the example size, we show only how this table can be read with 为了限制示例大小,我们只显示如何使用ctypes
:ctypes
读取此表:
>>> from ctypes import *
>>>
>>> class struct_frozen(Structure):
... _fields_ = [("name", c_char_p),
... ("code", POINTER(c_ubyte)),
... ("size", c_int)]
...
>>>
We have defined the struct _frozen data type, so we can get the pointer to the table:我们已经定义了struct _frozen数据类型,因此可以获得指向表的指针:
>>> FrozenTable = POINTER(struct_frozen)
>>> table = FrozenTable.in_dll(pythonapi, "PyImport_FrozenModules")
>>>
Since 由于table
is a pointer
to the array of struct_frozen
records, we can iterate over it, but we just have to make sure that our loop terminates, because pointers have no size. table
是指向struct_frozen
记录数组的pointer
,我们可以对其进行迭代,但我们只需确保循环终止,因为指针没有大小。Sooner or later it would probably crash with an access violation or whatever, so it’s better to break out of the loop when we hit the 它迟早会因访问冲突或其他原因而崩溃,因此最好在遇到NULL
entry:NULL
条目时跳出循环:
>>> for item in table:
... if item.name is None:
... break
... print(item.name.decode("ascii"), item.size)
...
_frozen_importlib 31764
_frozen_importlib_external 41499
__hello__ 161
__phello__ -161
__phello__.spam 161
>>>
The fact that standard Python has a frozen module and a frozen package (indicated by the negative 标准Python有一个冻结模块和一个冻结包(由负size
member) is not well known, it is only used for testing. size
成员表示)这一事实并不为人所知,它只用于测试。Try it out with 例如,尝试使用import __hello__
for example.import__hello__
。
Surprises惊喜¶
There are some edges in 在ctypes
where you might expect something other than what actually happens.ctypes
中有一些边缘,您可能会期望实际发生的事情以外的事情。
Consider the following example:考虑以下示例:
>>> 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
>>>
Hm. We certainly expected the last statement to print 嗯。我们当然希望最后一个语句打印3 4 1 2
. What happened? Here are the steps of the rc.a, rc.b = rc.b, rc.a
line above:3 4 1 2
。发生了什么?下面是上面rc.a, rc.b = rc.b, rc.a
行的步骤:
>>> temp0, temp1 = rc.b, rc.a
>>> rc.a = temp0
>>> rc.b = temp1
>>>
Note that 请注意,temp0
and temp1
are objects still using the internal buffer of the rc
object above. temp0
和temp1
是仍在使用上述rc对象的内部缓冲区的对象。So executing 因此,执行rc.a = temp0
copies the buffer contents of temp0
into rc
's buffer. rc.a=temp0
会将temp0
的缓冲区内容复制到rc
的缓冲区中。This, in turn, changes the contents of 这反过来又改变了temp1
. temp1
的内容。So, the last assignment 因此,最后一个赋值rc.b = temp1
, doesn’t have the expected effect.rc.b = temp1
没有预期的效果。
Keep in mind that retrieving sub-objects from Structure, Unions, and Arrays doesn’t copy the sub-object, instead it retrieves a wrapper object accessing the root-object’s underlying buffer.请记住,从Structure、Unions和Arrays检索子对象不会复制子对象,而是检索访问根对象底层缓冲区的包装器对象。
Another example that may behave differently from what one would expect is this:另一个可能与预期不同的例子是:
>>> s = c_char_p()
>>> s.value = b"abc def ghi"
>>> s.value
b'abc def ghi'
>>> s.value is s.value
False
>>>
Note
Objects instantiated from 从c_char_p
can only have their value set to bytes or integers.c_char_p
实例化的对象只能将其值设置为字节或整数。
Why is it printing 为什么打印为False
? False
?ctypes instances are objects containing a memory block plus some descriptors accessing the contents of the memory. ctypes实例是包含内存块和一些访问内存内容的描述符的对象。Storing a Python object in the memory block does not store the object itself, instead the 在内存块中存储Python对象不会存储对象本身,而是存储对象的contents
of the object is stored. contents
。Accessing the contents again constructs a new Python object each time!每次再次访问内容都会构造一个新的Python对象!
Variable-sized data types可变大小的数据类型¶
ctypes
provides some support for variable-sized arrays and structures.为可变大小的数组和结构提供了一些支持。
The resize()
function can be used to resize the memory buffer of an existing ctypes object. resize()
函数的作用是:调整现有ctypes
对象的内存缓冲区大小。The function takes the object as first argument, and the requested size in bytes as the second argument. 函数将对象作为第一个参数,将请求的字节大小作为第二个参数。The memory block cannot be made smaller than the natural memory block specified by the objects type, a 内存块不能小于对象类型指定的自然内存块,如果尝试这样做,将引发ValueError
is raised if this is tried:ValueError
:
>>> 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
>>>
This is nice and fine, but how would one access the additional elements contained in this array? 这很好,但是如何访问这个数组中包含的其他元素呢?Since the type still only knows about 4 elements, we get errors accessing other elements:由于类型仍然只知道大约4个元素,因此访问其他元素时会出错:
>>> short_array[:]
[0, 0, 0, 0]
>>> short_array[7]
Traceback (most recent call last):
...
IndexError: invalid index
>>>
Another way to use variable-sized data types with 将可变大小的数据类型与ctypes
is to use the dynamic nature of Python, and (re-)define the data type after the required size is already known, on a case by case basis.ctypes
结合使用的另一种方法是使用Python的动态特性,并在已知所需大小后,根据具体情况重新定义数据类型。
ctypes referencectypes参考¶
Foreign functions外部函数¶
As explained in the previous section, foreign functions can be accessed as attributes of loaded shared libraries. 如前一节所述,外部函数可以作为加载的共享库的属性进行访问。The function objects created in this way by default accept any number of arguments, accept any ctypes data instances as arguments, and return the default result type specified by the library loader. 默认情况下,以这种方式创建的函数对象接受任意数量的参数,接受任意ctypes数据实例作为参数,并返回库加载器指定的默认结果类型。They are instances of a private class:它们是私有类的实例:
-
class
ctypes.
_FuncPtr
¶ Base class for C callable foreign functions.C可调用外部函数的基类。Instances of foreign functions are also C compatible data types; they represent C function pointers.外部函数的实例也是C兼容的数据类型;它们表示C函数指针。This behavior can be customized by assigning to special attributes of the foreign function object.这种行为可以通过指定给外部函数对象的特殊属性来定制。-
restype
¶ Assign a ctypes type to specify the result type of the foreign function.指定ctypes类型以指定外部函数的结果类型。Use使用None
for void, a function not returning anything.None
表示void,该函数不返回任何内容。It is possible to assign a callable Python object that is not a ctypes type, in this case the function is assumed to return a C int, and the callable will be called with this integer, allowing further processing or error checking.可以分配一个不是ctypes类型的可调用Python对象,在这种情况下,假设函数返回一个C int,并用这个整数调用可调用对象,从而允许进一步处理或错误检查。Using this is deprecated, for more flexible post processing or error checking use a ctypes data type as不推荐使用此选项,为了更灵活的后期处理或错误检查,请将ctypes数据类型用作restype
and assign a callable to theerrcheck
attribute.restype
,并将可调用项分配给errcheck
属性。
-
argtypes
¶ Assign a tuple of ctypes types to specify the argument types that the function accepts.分配ctypes类型的元组以指定函数接受的参数类型。Functions using the使用stdcall
calling convention can only be called with the same number of arguments as the length of this tuple; functions using the C calling convention accept additional, unspecified arguments as well.stdcall
调用约定的函数只能使用与此元组长度相同的参数数进行调用;使用C调用约定的函数也接受其他未指定的参数。When a foreign function is called, each actual argument is passed to the
from_param()
class method of the items in theargtypes
tuple, this method allows adapting the actual argument to an object that the foreign function accepts. For example, ac_char_p
item in theargtypes
tuple will convert a string passed as argument into a bytes object using ctypes conversion rules.New: It is now possible to put items in argtypes which are not ctypes types, but each item must have a新增:现在可以将项目放入不是ctypes类型的argtypes中,但每个项目必须有一个from_param()
method which returns a value usable as argument (integer, string, ctypes instance).from_param()
方法,该方法返回一个可用作参数的值(integer、string、ctypes实例)。This allows defining adapters that can adapt custom objects as function parameters.这允许定义可以将自定义对象调整为函数参数的适配器。
-
errcheck
¶ Assign a Python function or another callable to this attribute.将Python函数或其他可调用函数分配给该属性。The callable will be called with three or more arguments:将使用三个或更多参数调用可调用项:-
callable
(result, func, arguments) result
is what the foreign function returns, as specified by the是外部函数返回的内容,由restype
attribute.restype
属性指定。func
is the foreign function object itself, this allows reusing the same callable object to check or post process the results of several functions.是外部函数对象本身,这允许重用相同的可调用对象来检查或后处理多个函数的结果。arguments
is a tuple containing the parameters originally passed to the function call, this allows specializing the behavior on the arguments used.是一个元组,包含最初传递给函数调用的参数,这允许专门化所用参数的行为。
The object that this function returns will be returned from the foreign function call, but it can also check the result value and raise an exception if the foreign function call failed.此函数返回的对象将从外部函数调用返回,但它也可以检查结果值,并在外部函数调用失败时引发异常。-
-
-
exception
ctypes.
ArgumentError
¶ This exception is raised when a foreign function call cannot convert one of the passed arguments.当外部函数调用无法转换传递的参数之一时,会引发此异常。
On Windows, when a foreign function call raises a system exception (for example, due to an access violation), it will be captured and replaced with a suitable Python exception. 在Windows上,当外部函数调用引发系统异常(例如,由于访问冲突)时,它将被捕获并替换为合适的Python异常。Further, an auditing event 此外,将引发带有参数代码的审计事件ctypes.seh_exception
with argument code
will be raised, allowing an audit hook to replace the exception with its own.ctypes.seh_exception
,允许审计钩子将异常替换为自己的异常。
Some ways to invoke foreign function calls may raise an auditing event 某些调用外部函数调用的方法可能会引发带有参数ctypes.call_function
with arguments function pointer
and arguments
.function pointer
和arguments
的审核事件ctypes.call_function
。
Function prototypes功能原型¶
Foreign functions can also be created by instantiating function prototypes. 还可以通过实例化函数原型来创建外部函数。Function prototypes are similar to function prototypes in C; they describe a function (return type, argument types, calling convention) without defining an implementation. 功能原型类似于C语言中的功能原型;它们描述函数(返回类型、参数类型、调用约定)而不定义实现。The factory functions must be called with the desired result type and the argument types of the function, and can be used as decorator factories, and as such, be applied to functions through the 工厂函数必须使用所需的结果类型和函数的参数类型进行调用,并且可以用作装饰工厂,因此可以通过@wrapper
syntax. @wrapper
语法应用于函数。See Callback functions for examples.有关示例,请参阅回调函数。
-
ctypes.
CFUNCTYPE
(restype, *argtypes, use_errno=False, use_last_error=False)¶ The returned function prototype creates functions that use the standard C calling convention.返回的函数原型创建使用标准C调用约定的函数。The function will release the GIL during the call.函数将在调用期间释放GIL。If use_errno is set to true, the ctypes private copy of the systemerrno
variable is exchanged with the realerrno
value before and after the call; use_last_error does the same for the Windows error code.
-
ctypes.
WINFUNCTYPE
(restype, *argtypes, use_errno=False, use_last_error=False)¶ Windows only: The returned function prototype creates functions that use the
stdcall
calling convention, except on Windows CE whereWINFUNCTYPE()
is the same asCFUNCTYPE()
. The function will release the GIL during the call. use_errno and use_last_error have the same meaning as above.
-
ctypes.
PYFUNCTYPE
(restype, *argtypes)¶ The returned function prototype creates functions that use the Python calling convention.返回的函数原型创建使用Python调用约定的函数。The function will not release the GIL during the call.函数在调用期间不会释放GIL。
Function prototypes created by these factory functions can be instantiated in different ways, depending on the type and number of the parameters in the call:根据调用中参数的类型和数量,这些工厂函数创建的函数原型可以以不同的方式进行实例化:
prototype
(address)
Returns a foreign function at the specified address which must be an integer.返回指定地址处的外部函数,该函数必须是整数。
prototype
(callable)
Create a C callable function (a callback function) from a Python callable.从Pythoncallable创建C可调用函数(回调函数)。
prototype
(func_spec[, paramflags])
Returns a foreign function exported by a shared library.返回共享库导出的外部函数。func_specmust be a 2-tuple必须是2元组(name_or_ordinal, library)
.(name_or_ordinal, library)
。The first item is the name of the exported function as string, or the ordinal of the exported function as small integer.第一项是作为字符串的导出函数的名称,或作为小整数的导出函数序号。The second item is the shared library instance.第二项是共享库实例。
prototype
(vtbl_index, name[, paramflags[, iid]])Returns a foreign function that will call a COM method. vtbl_index is the index into the virtual function table, a small non-negative integer. name is name of the COM method. iid is an optional pointer to the interface identifier which is used in extended error reporting.
COM methods use a special calling convention: They require a pointer to the COM interface as first argument, in addition to those parameters that are specified in the
argtypes
tuple.
The optional paramflags parameter creates foreign function wrappers with much more functionality than the features described above.可选的paramflags参数创建的外部函数包装器的功能比上面描述的功能多得多。paramflags
must be a tuple of the same length as必须是与argtypes
.argtypes
长度相同的元组。
Each item in this tuple contains further information about a parameter, it must be a tuple containing one, two, or three items.此元组中的每个项都包含有关参数的更多信息,它必须是包含一个、两个或三个项的元组。
The first item is an integer containing a combination of direction flags for the parameter:第一项是包含参数方向标志组合的整数:
- 1
Specifies an input parameter to the function.指定函数的输入参数。- 2
Output parameter.输出参数。The foreign function fills in a value.外部函数填充一个值。- 4
Input parameter which defaults to the integer zero.默认为整数零的输入参数。
The optional second item is the parameter name as string.可选的第二项是字符串形式的参数名。If this is specified, the foreign function can be called with named parameters.如果指定了此选项,则可以使用命名参数调用外部函数。
The optional third item is the default value for this parameter.可选的第三项是此参数的默认值。
This example demonstrates how to wrap the Windows 此示例演示如何包装Windows MessageBoxW
function so that it supports default parameters and named arguments. MessageBoxW
函数,以便它支持默认参数和命名参数。The C declaration from the windows header file is this:windows头文件中的C声明如下:
WINUSERAPI int WINAPI
MessageBoxW(
HWND hWnd,
LPCWSTR lpText,
LPCWSTR lpCaption,
UINT uType);
Here is the wrapping with 这是带有ctypes
:ctypes
的包装:
>>> from ctypes import c_int, WINFUNCTYPE, windll
>>> from ctypes.wintypes import HWND, LPCWSTR, UINT
>>> prototype = WINFUNCTYPE(c_int, HWND, LPCWSTR, LPCWSTR, UINT)
>>> paramflags = (1, "hwnd", 0), (1, "text", "Hi"), (1, "caption", "Hello from ctypes"), (1, "flags", 0)
>>> MessageBox = prototype(("MessageBoxW", windll.user32), paramflags)
The 现在可以通过以下方式调用MessageBox
foreign function can now be called in these ways:MessageBox
外部函数:
>>> MessageBox()
>>> MessageBox(text="Spam, spam, spam")
>>> MessageBox(flags=2, text="foo bar")
A second example demonstrates output parameters. 第二个示例演示了输出参数。The win32 win32 GetWindowRect
function retrieves the dimensions of a specified window by copying them into RECT
structure that the caller has to supply. GetWindowRect
函数通过将指定窗口的维度复制到调用程序必须提供的RECT
结构中来检索这些维度。Here is the C declaration:以下是C声明:
WINUSERAPI BOOL WINAPI
GetWindowRect(
HWND hWnd,
LPRECT lpRect);
Here is the wrapping with 这是带有ctypes
: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)
>>>
Functions with output parameters will automatically return the output parameter value if there is a single one, or a tuple containing the output parameter values when there are more than one, so the GetWindowRect function now returns a RECT instance, when called.如果只有一个输出参数值,则带有输出参数的函数将自动返回输出参数值;如果有多个输出参数,则包含输出参数值的元组将自动返回,因此GetWindowRect函数现在在调用时返回RECT实例。
Output parameters can be combined with the errcheck
protocol to do further output processing and error checking. The win32 GetWindowRect
api function returns a BOOL
to signal success or failure, so this function could do the error checking, and raises an exception when the api call failed:
>>> def errcheck(result, func, args):
... if not result:
... raise WinError()
... return args
...
>>> GetWindowRect.errcheck = errcheck
>>>
If the 如果errcheck
function returns the argument tuple it receives unchanged, ctypes
continues the normal processing it does on the output parameters. errcheck
函数返回它收到的参数元组不变,则ctypes
将继续它对输出参数所做的正常处理。If you want to return a tuple of window coordinates instead of a 如果要返回窗口坐标元组而不是RECT
instance, you can retrieve the fields in the function and return them instead, the normal processing will no longer take place:RECT
实例,可以检索函数中的字段并返回它们,正常处理将不再发生:
>>> 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
>>>
Utility functions实用程序功能¶
-
ctypes.
addressof
(obj)¶ Returns the address of the memory buffer as integer.以整数形式返回内存缓冲区的地址。objmust be an instance of a ctypes type.必须是ctypes类型的实例。Raises an auditing event使用参数ctypes.addressof
with argumentobj
.obj
引发审核事件ctypes.addressof
。
-
ctypes.
alignment
(obj_or_type)¶ Returns the alignment requirements of a ctypes type.返回ctypes类型的对齐要求。obj_or_typemust be a ctypes type or instance.必须是ctypes类型或实例。
-
ctypes.
byref
(obj[, offset])¶ Returns a light-weight pointer to obj, which must be an instance of a ctypes type.返回指向obj的轻量级指针,该指针必须是ctypes类型的实例。offsetdefaults to zero, and must be an integer that will be added to the internal pointer value.默认为零,并且必须是将添加到内部指针值的整数。byref(obj, offset)
corresponds to this C code:对应于此C代码:(((char *)&obj) + offset)
The returned object can only be used as a foreign function call parameter.返回的对象只能用作外部函数调用参数。It behaves similar to它的行为类似于pointer(obj)
, but the construction is a lot faster.pointer(obj)
,但构造速度要快得多。
-
ctypes.
cast
(obj, type)¶ This function is similar to the cast operator in C.此函数类似于C中的转换运算符。It returns a new instance of type which points to the same memory block as obj.它返回一个type的新实例,该实例指向与obj相同的内存块。typemust be a pointer type, and obj must be an object that can be interpreted as a pointer.必须是指针类型,obj必须是可以解释为指针的对象。
-
ctypes.
create_string_buffer
(init_or_size, size=None)¶ This function creates a mutable character buffer.此函数用于创建可变字符缓冲区。The returned object is a ctypes array of返回的对象是c_char
.c_char
的ctypes数组。init_or_size
must be an integer which specifies the size of the array, or a bytes object which will be used to initialize the array items.必须是指定数组大小的整数,或者是将用于初始化数组项的字节对象。If a bytes object is specified as first argument, the buffer is made one item larger than its length so that the last element in the array is a NUL termination character.如果将bytes对象指定为第一个参数,则缓冲区将比其长度大一项,以便数组中的最后一个元素是NUL终止字符。An integer can be passed as second argument which allows specifying the size of the array if the length of the bytes should not be used.整数可以作为第二个参数传递,如果不应使用字节长度,则可以指定数组的大小。Raises an auditing event使用参数ctypes.create_string_buffer
with argumentsinit
,size
.init
、size
引发审核事件ctypes.create_string_buffer
。
-
ctypes.
create_unicode_buffer
(init_or_size, size=None)¶ This function creates a mutable unicode character buffer.此函数用于创建可变unicode字符缓冲区。The returned object is a ctypes array of返回的对象是c_wchar
.c_wchar
的ctypes数组。init_or_size
must be an integer which specifies the size of the array, or a string which will be used to initialize the array items.必须是指定数组大小的整数,或将用于初始化数组项的字符串。If a string is specified as first argument, the buffer is made one item larger than the length of the string so that the last element in the array is a NUL termination character.如果将字符串指定为第一个参数,则缓冲区将比字符串长度大一项,以便数组中的最后一个元素是NUL终止字符。An integer can be passed as second argument which allows specifying the size of the array if the length of the string should not be used.整数可以作为第二个参数传递,如果不应使用字符串的长度,则可以指定数组的大小。Raises an auditing event使用参数ctypes.create_unicode_buffer
with argumentsinit
,size
.init
、size
引发审核事件ctypes.create_unicode_buffer
。
-
ctypes.
DllCanUnloadNow
()¶ Windows only: This function is a hook which allows implementing in-process COM servers with ctypes.仅限Windows:此函数是一个钩子,允许使用ctype实现进程内COM服务器。It is called from the DllCanUnloadNow function that the _ctypes extension dll exports._ctypes扩展dll导出的DllCanUnloadNow函数调用它。
-
ctypes.
DllGetClassObject
()¶ Windows only: This function is a hook which allows implementing in-process COM servers with ctypes.仅限Windows:此函数是一个钩子,允许使用ctype实现进程内COM服务器。It is called from the DllGetClassObject function that the_ctypes
extension dll exports._ctypes
扩展dll导出的DllGetClassObject函数调用它。
-
ctypes.util.
find_library
(name)¶ Try to find a library and return a pathname.尝试查找库并返回路径名。name is the library name without any prefix likelib
, suffix like.so
,.dylib
or version number (this is the form used for the posix linker option-l
). If no library can be found, returnsNone
.The exact functionality is system dependent.具体功能取决于系统。
-
ctypes.util.
find_msvcrt
()¶ Windows only: return the filename of the VC runtime library used by Python, and by the extension modules.仅限Windows:返回Python和扩展模块使用的VC运行库的文件名。If the name of the library cannot be determined,如果无法确定库的名称,则返回None
is returned.None
。If you need to free memory, for example, allocated by an extension module with a call to the如果您需要释放内存,例如,通过调用free(void *)
, it is important that you use the function in the same library that allocated the memory.free(void *)
来释放扩展模块分配的内存,请务必使用分配内存的同一库中的函数。
-
ctypes.
FormatError
([code])¶ Windows only: Returns a textual description of the error code code.仅限Windows:返回错误代码code的文本描述。If no error code is specified, the last error code is used by calling the Windows api function GetLastError.如果未指定错误代码,则通过调用Windows api函数GetLastError使用最后一个错误代码。
-
ctypes.
GetLastError
()¶ Windows only: Returns the last error code set by Windows in the calling thread.仅限Windows:返回Windows在调用线程中设置的最后一个错误代码。This function calls the Windows GetLastError() function directly, it does not return the ctypes-private copy of the error code.此函数直接调用WindowsGetLastError()
函数,它不返回错误代码的ctypes私有副本。
-
ctypes.
get_errno
()¶ Returns the current value of the ctypes-private copy of the system
errno
variable in the calling thread.Raises an auditing event
ctypes.get_errno
with no arguments.
-
ctypes.
get_last_error
()¶ Windows only: returns the current value of the ctypes-private copy of the system仅限Windows:返回调用线程中系统LastError
variable in the calling thread.LastError
变量的ctypes私有副本的当前值。Raises an auditing event
ctypes.get_last_error
with no arguments.
-
ctypes.
memmove
(dst, src, count)¶ Same as the standard C memmove library function: copies count bytes from src to dst. dst and src must be integers or ctypes instances that can be converted to pointers.
-
ctypes.
memset
(dst, c, count)¶ Same as the standard C memset library function: fills the memory block at address dst with count bytes of value c. dst must be an integer specifying an address, or a ctypes instance.
-
ctypes.
POINTER
(type)¶ This factory function creates and returns a new ctypes pointer type.这个工厂函数创建并返回一个新的ctypes指针类型。Pointer types are cached and reused internally, so calling this function repeatedly is cheap.指针类型在内部被缓存和重用,因此重复调用此函数的成本很低。typemust be a ctypes type.必须是ctypes类型。
-
ctypes.
pointer
(obj)¶ This function creates a new pointer instance, pointing to obj.此函数用于创建一个指向obj的新指针实例。The returned object is of the type返回的对象类型为POINTER(type(obj))
.POINTER(type(obj))
。Note: If you just want to pass a pointer to an object to a foreign function call, you should use注意:如果您只想将指向对象的指针传递给外部函数调用,那么应该使用byref(obj)
which is much faster.byref(obj)
,这要快得多。
-
ctypes.
resize
(obj, size)¶ This function resizes the internal memory buffer of obj, which must be an instance of a ctypes type. It is not possible to make the buffer smaller than the native size of the objects type, as given by
sizeof(type(obj))
, but it is possible to enlarge the buffer.
-
ctypes.
set_errno
(value)¶ Set the current value of the ctypes-private copy of the system
errno
variable in the calling thread to value and return the previous value.Raises an auditing event
ctypes.set_errno
with argumenterrno
.
-
ctypes.
set_last_error
(value)¶ Windows only: set the current value of the ctypes-private copy of the system
LastError
variable in the calling thread to value and return the previous value.Raises an auditing event
ctypes.set_last_error
with argumenterror
.
-
ctypes.
sizeof
(obj_or_type)¶ Returns the size in bytes of a ctypes type or instance memory buffer.返回ctypes类型或实例内存缓冲区的字节大小。Does the same as the C执行与Csizeof
operator.sizeof
运算符相同的操作。
-
ctypes.
string_at
(address, size=- 1)¶ This function returns the C string starting at memory address address as a bytes object.此函数将从内存地址address开始的C字符串作为字节对象返回。If size is specified, it is used as size, otherwise the string is assumed to be zero-terminated.如果指定了size,则将其用作size,否则假定字符串以零结尾。Raises an auditing event
ctypes.string_at
with argumentsaddress
,size
.
-
ctypes.
WinError
(code=None, descr=None)¶ Windows only: this function is probably the worst-named thing in ctypes.仅限Windows:此函数可能是ctypes中命名最差的函数。It creates an instance of OSError.它创建OSError的实例。If code is not specified,GetLastError
is called to determine the error code. If descr is not specified,FormatError()
is called to get a textual description of the error.Changed in version 3.3:版本3.3中更改:An instance of用于创建WindowsError
used to be created.WindowsError
的实例。
-
ctypes.
wstring_at
(address, size=- 1)¶ This function returns the wide character string starting at memory address address as a string.此函数将从内存地址address开始的宽字符串作为字符串返回。If size is specified, it is used as the number of characters of the string, otherwise the string is assumed to be zero-terminated.如果指定了size,则将其用作字符串的字符数,否则假定字符串以零结尾。Raises an auditing event使用参数ctypes.wstring_at
with argumentsaddress
,size
.address
、size
引发审核事件ctypes.wstring_at
。
Data types数据类型¶
-
class
ctypes.
_CData
¶ This non-public class is the common base class of all ctypes data types.这个非公共类是所有ctypes数据类型的公共基类。Among other things, all ctypes type instances contain a memory block that hold C compatible data; the address of the memory block is returned by the除此之外,所有ctypes类型实例都包含一个存储C兼容数据的内存块;内存块的地址由addressof()
helper function.addressof()
助手函数返回。Another instance variable is exposed as另一个实例变量显示为_objects
; this contains other Python objects that need to be kept alive in case the memory block contains pointers._objects
;它包含其他需要保持活动状态的Python对象,以防内存块包含指针。Common methods of ctypes data types, these are all class methods (to be exact, they are methods of the metaclass):
-
from_buffer
(source[, offset])¶ This method returns a ctypes instance that shares the buffer of the source object. The source object must support the writeable buffer interface. The optional offset parameter specifies an offset into the source buffer in bytes; the default is zero. If the source buffer is not large enough a
ValueError
is raised.Raises an auditing event
ctypes.cdata/buffer
with argumentspointer
,size
,offset
.
-
from_buffer_copy
(source[, offset])¶ This method creates a ctypes instance, copying the buffer from the source object buffer which must be readable. The optional offset parameter specifies an offset into the source buffer in bytes; the default is zero. If the source buffer is not large enough a
ValueError
is raised.Raises an auditing event使用参数ctypes.cdata/buffer
with argumentspointer
,size
,offset
.pointer
、size
、offset
引发审核事件ctypes.cdata/buffer
。
-
from_address
(address)¶ This method returns a ctypes type instance using the memory specified by address which must be an integer.此方法使用address指定的内存返回ctypes类型实例,该内存必须是整数。This method, and others that indirectly call this method, raises an auditing event此方法以及其他间接调用此方法的方法将引发一个具有参数ctypes.cdata
with argumentaddress
.address
的审核事件ctypes.cdata
。
-
from_param
(obj)¶ This method adapts obj to a ctypes type.此方法将obj调整为ctypes类型。It is called with the actual object used in a foreign function call when the type is present in the foreign function’s当类型存在于外部函数的argtypes
tuple; it must return an object that can be used as a function call parameter.argtypes
元组中时,使用外部函数调用中使用的实际对象来调用它;它必须返回一个可以用作函数调用参数的对象。All ctypes data types have a default implementation of this classmethod that normally returns obj if that is an instance of the type.所有ctypes数据类型都有这个类方法的默认实现,如果obj是该类型的实例,它通常会返回obj。Some types accept other objects as well.某些类型也接受其他对象。
-
in_dll
(library, name)¶ This method returns a ctypes type instance exported by a shared library.此方法返回由共享库导出的ctypes类型实例。name is the name of the symbol that exports the data, library is the loaded shared library.name是导出数据的符号的名称,library是加载的共享库。
Common instance variables of ctypes data types:ctypes数据类型的常见实例变量:-
_b_base_
¶ Sometimes ctypes data instances do not own the memory block they contain, instead they share part of the memory block of a base object.有时ctypes数据实例并不拥有它们包含的内存块,而是共享基本对象的部分内存块。The_b_base_
read-only member is the root ctypes object that owns the memory block._b_base_
只读成员是拥有内存块的根ctypes对象。
-
_b_needsfree_
¶ This read-only variable is true when the ctypes data instance has allocated the memory block itself, false otherwise.当ctypes数据实例已分配内存块本身时,此只读变量为true
,否则为false
。
-
_objects
¶ This member is either该成员要么是None
or a dictionary containing Python objects that need to be kept alive so that the memory block contents is kept valid.None
,要么是包含需要保持活动状态的Python对象的字典,以便内存块内容保持有效。This object is only exposed for debugging; never modify the contents of this dictionary.此对象仅用于调试;永远不要修改这本词典的内容。
-
Fundamental data types基本数据类型¶
-
class
ctypes.
_SimpleCData
¶ This non-public class is the base class of all fundamental ctypes data types.这个非公共类是所有基本ctypes数据类型的基类。It is mentioned here because it contains the common attributes of the fundamental ctypes data types.这里之所以提到它,是因为它包含基本ctypes数据类型的公共属性。_SimpleCData
is a subclass of是_CData
, so it inherits their methods and attributes._CData
的子类,因此它继承了它们的方法和属性。ctypes data types that are not and do not contain pointers can now be pickled.现在可以对不包含指针和不包含指针的ctypes数据类型进行pickle处理。Instances have a single attribute:实例具有单个属性:-
value
¶ This attribute contains the actual value of the instance.此属性包含实例的实际值。For integer and pointer types, it is an integer, for character types, it is a single character bytes object or string, for character pointer types it is a Python bytes object or string.对于整数和指针类型,它是一个整数;对于字符类型,它就是一个单字符字节对象或字符串;对于字符指针类型,则是一个Python字节对象或串。When the从ctypes实例检索value
attribute is retrieved from a ctypes instance, usually a new object is returned each time.value
属性时,通常每次都会返回一个新对象。ctypes
does not implement original object return, always a new object is constructed. The same is true for all other ctypes object instances.
-
Fundamental data types, when returned as foreign function call results, or, for example, by retrieving structure field members or array items, are transparently converted to native Python types. 当作为外部函数调用结果返回时,或者例如通过检索结构字段成员或数组项返回时,基本数据类型将透明地转换为本机Python类型。In other words, if a foreign function has a restype
of c_char_p
, you will always receive a Python bytes object, not a c_char_p
instance.
Subclasses of fundamental data types do not inherit this behavior. So, if a foreign functions restype
is a subclass of c_void_p
, you will receive an instance of this subclass from the function call. Of course, you can get the value of the pointer by accessing the value
attribute.
These are the fundamental ctypes data types:以下是基本的ctypes数据类型:
-
class
ctypes.
c_byte
¶ Represents the C signed char datatype, and interprets the value as small integer.
The constructor accepts an optional integer initializer; no overflow checking is done.构造函数接受可选的整数初始值设定项;没有进行溢出检查。
-
class
ctypes.
c_char
¶ Represents the C char datatype, and interprets the value as a single character.表示Cchar数据类型,并将该值解释为单个字符。The constructor accepts an optional string initializer, the length of the string must be exactly one character.构造函数接受可选的字符串初始值设定项,字符串的长度必须正好是一个字符。
-
class
ctypes.
c_char_p
¶ Represents the C char* datatype when it points to a zero-terminated string.
For a general character pointer that may also point to binary data,对于也可能指向二进制数据的通用字符指针,必须使用POINTER(c_char)
must be used.POINTER(c_char)
。The constructor accepts an integer address, or a bytes object.构造函数接受整数地址或字节对象。
-
class
ctypes.
c_double
¶ Represents the C double datatype.
The constructor accepts an optional float initializer.构造函数接受可选的浮点初始值设定项。
-
class
ctypes.
c_longdouble
¶ Represents the C long double datatype.
The constructor accepts an optional float initializer.构造函数接受可选的浮点初始值设定项。On platforms wheresizeof(long double) == sizeof(double)
it is an alias toc_double
.
-
class
ctypes.
c_float
¶ Represents the C float datatype.
The constructor accepts an optional float initializer.构造函数接受可选的浮点初始值设定项。
-
class
ctypes.
c_int
¶ Represents the C signed int datatype.
The constructor accepts an optional integer initializer; no overflow checking is done.构造函数接受可选的整数初始值设定项;没有进行溢出检查。On platforms wheresizeof(int) == sizeof(long)
it is an alias toc_long
.
-
class
ctypes.
c_int64
¶ Represents the C 64-bit signed int datatype. Usually an alias for
c_longlong
.
-
class
ctypes.
c_long
¶ Represents the C signed long datatype.
The constructor accepts an optional integer initializer; no overflow checking is done.构造函数接受可选的整数初始值设定项;没有进行溢出检查。
-
class
ctypes.
c_longlong
¶ Represents the C signed long long datatype.
The constructor accepts an optional integer initializer; no overflow checking is done.构造函数接受可选的整数初始值设定项;没有进行溢出检查。
-
class
ctypes.
c_short
¶ Represents the C signed short datatype.
The constructor accepts an optional integer initializer; no overflow checking is done.构造函数接受可选的整数初始值设定项;没有进行溢出检查。
-
class
ctypes.
c_size_t
¶ Represents the C
size_t
datatype.
-
class
ctypes.
c_ssize_t
¶ Represents the C
ssize_t
datatype.New in version 3.2.版本3.2中新增。
-
class
ctypes.
c_ubyte
¶ Represents the C unsigned char datatype, it interprets the value as small integer.
The constructor accepts an optional integer initializer; no overflow checking is done.构造函数接受可选的整数初始值设定项;没有进行溢出检查。
-
class
ctypes.
c_uint
¶ Represents the C unsigned int datatype.
The constructor accepts an optional integer initializer; no overflow checking is done.构造函数接受可选的整数初始值设定项;没有进行溢出检查。On platforms wheresizeof(int) == sizeof(long)
it is an alias forc_ulong
.
-
class
ctypes.
c_uint64
¶ Represents the C 64-bit unsigned int datatype. Usually an alias for
c_ulonglong
.
-
class
ctypes.
c_ulong
¶ Represents the C unsigned long datatype.
The constructor accepts an optional integer initializer; no overflow checking is done.构造函数接受可选的整数初始值设定项;没有进行溢出检查。
-
class
ctypes.
c_ulonglong
¶ Represents the C unsigned long long datatype.
The constructor accepts an optional integer initializer; no overflow checking is done.构造函数接受可选的整数初始值设定项;没有进行溢出检查。
-
class
ctypes.
c_ushort
¶ Represents the C unsigned short datatype.
The constructor accepts an optional integer initializer; no overflow checking is done.构造函数接受可选的整数初始值设定项;没有进行溢出检查。
-
class
ctypes.
c_void_p
¶ Represents the C void* type. The value is represented as integer.
The constructor accepts an optional integer initializer.构造函数接受可选的整数初始值设定项。
-
class
ctypes.
c_wchar
¶ Represents the C
wchar_t
datatype, and interprets the value as a single character unicode string.The constructor accepts an optional string initializer, the length of the string must be exactly one character.构造函数接受可选的字符串初始值设定项,字符串的长度必须正好是一个字符。
-
class
ctypes.
c_wchar_p
¶ Represents the C wchar_t* datatype, which must be a pointer to a zero-terminated wide character string.
The constructor accepts an integer address, or a string.构造函数接受整数地址或字符串。
-
class
ctypes.
c_bool
¶ Represent the C bool datatype (more accurately, _Bool from C99). Its value can be
True
orFalse
, and the constructor accepts any object that has a truth value.
-
class
ctypes.
HRESULT
¶ Windows only: Represents a仅限Windows:表示HRESULT
value, which contains success or error information for a function or method call.HRESULT
值,其中包含函数或方法调用的成功或错误信息。
-
class
ctypes.
py_object
¶ Represents the C PyObject* datatype. Calling this without an argument creates a
NULL
PyObject* pointer.
The ctypes.wintypes
module provides quite some other Windows specific data types, for example HWND
, WPARAM
, or DWORD
. Some useful structures like MSG
or RECT
are also defined.
Structured data types结构化数据类型¶
-
class
ctypes.
Union
(*args, **kw)¶ Abstract base class for unions in native byte order.按本机字节顺序的联合的抽象基类。
-
class
ctypes.
BigEndianStructure
(*args, **kw)¶ Abstract base class for structures in big endian byte order.以大端字节顺序表示的结构的抽象基类。
-
class
ctypes.
LittleEndianStructure
(*args, **kw)¶ Abstract base class for structures in little endian byte order.以小端字节顺序表示的结构的抽象基类。
Structures with non-native byte order cannot contain pointer type fields, or any other data types containing pointer type fields.具有非本机字节顺序的结构不能包含指针类型字段,也不能包含任何其他含有指针类型字段的数据类型。
-
class
ctypes.
Structure
(*args, **kw)¶ Abstract base class for structures in native byte order.按原生字节顺序的结构的抽象基类。Concrete structure and union types must be created by subclassing one of these types, and at least define a具体的结构和联合类型必须通过对其中一个类型进行子类化来创建,并且至少要定义一个_fields_
class variable._fields_
类变量。ctypes
will create descriptors which allow reading and writing the fields by direct attribute accesses.将创建允许通过直接属性访问读取和写入字段的描述符。These are the这些是-
_fields_
¶ A sequence defining the structure fields.定义结构字段的序列。The items must be 2-tuples or 3-tuples.这些项必须是2元组或3元组。The first item is the name of the field, the second item specifies the type of the field; it can be any ctypes data type.第一项是字段的名称,第二项指定字段的类型;它可以是任何ctypes数据类型。For integer type fields like对于像c_int
, a third optional item can be given.c_int
这样的整数类型字段,可以给出第三个可选项。It must be a small positive integer defining the bit width of the field.它必须是一个小的正整数,用于定义字段的位宽度。Field names must be unique within one structure or union.字段名在一个结构或联合中必须唯一。This is not checked, only one field can be accessed when names are repeated.未选中此选项,重复名称时只能访问一个字段。It is possible to define the
_fields_
class variable after the class statement that defines the Structure subclass, this allows creating data types that directly or indirectly reference themselves:class List(Structure):
pass
List._fields_ = [("pnext", POINTER(List)),
...
]The
_fields_
class variable must, however, be defined before the type is first used (an instance is created,sizeof()
is called on it, and so on). Later assignments to the_fields_
class variable will raise an AttributeError.It is possible to define sub-subclasses of structure types, they inherit the fields of the base class plus the可以定义结构类型的子子类,它们继承基类的字段加上子类中定义的_fields_
defined in the sub-subclass, if any._fields_
(如果有的话)。
-
_pack_
¶ An optional small integer that allows overriding the alignment of structure fields in the instance.一个可选的小整数,允许重写实例中结构字段的对齐方式。_pack_
must already be defined when_fields_
is assigned, otherwise it will have no effect.
-
_anonymous_
¶ An optional sequence that lists the names of unnamed (anonymous) fields.
_anonymous_
must be already defined when_fields_
is assigned, otherwise it will have no effect.The fields listed in this variable must be structure or union type fields.此变量中列出的字段必须是结构或联合类型字段。ctypes
will create descriptors in the structure type that allows accessing the nested fields directly, without the need to create the structure or union field.将以允许直接访问嵌套字段的结构类型创建描述符,而无需创建结构或联合字段。Here is an example type (Windows):
class _U(Union):
_fields_ = [("lptdesc", POINTER(TYPEDESC)),
("lpadesc", POINTER(ARRAYDESC)),
("hreftype", HREFTYPE)]
class TYPEDESC(Structure):
_anonymous_ = ("u",)
_fields_ = [("u", _U),
("vt", VARTYPE)]The
TYPEDESC
structure describes a COM data type, thevt
field specifies which one of the union fields is valid. Since theu
field is defined as anonymous field, it is now possible to access the members directly off the TYPEDESC instance.td.lptdesc
andtd.u.lptdesc
are equivalent, but the former is faster since it does not need to create a temporary union instance:td = TYPEDESC()
td.vt = VT_PTR
td.lptdesc = POINTER(some_type)
td.u.lptdesc = POINTER(some_type)
It is possible to define sub-subclasses of structures, they inherit the fields of the base class.可以定义结构的子子类,它们继承基类的字段。If the subclass definition has a separate如果子类定义有一个单独的_fields_
variable, the fields specified in this are appended to the fields of the base class._fields_
变量,则其中指定的字段将附加到基类的字段中。Structure and union constructors accept both positional and keyword arguments.结构构造函数和联合构造函数都接受位置参数和关键字参数。Positional arguments are used to initialize member fields in the same order as they are appear in_fields_
. Keyword arguments in the constructor are interpreted as attribute assignments, so they will initialize_fields_
with the same name, or create new attributes for names not present in_fields_
.-
Arrays and pointers数组和指针¶
-
class
ctypes.
Array
(*args)¶ Abstract base class for arrays.数组的抽象基类。The recommended way to create concrete array types is by multiplying any创建具体数组类型的推荐方法是将任何ctypes
data type with a non-negative integer.ctypes
数据类型与非负整数相乘。Alternatively, you can subclass this type and define_length_
and_type_
class variables.Array elements can be read and written using standard subscript and slice accesses; for slice reads, the resulting object is not itself an数组元素可以使用标准下标和切片访问进行读写;对于切片读取,生成的对象本身不是Array
.Array
。-
_length_
¶ A positive integer specifying the number of elements in the array.一个正整数,指定数组中的元素数。Out-of-range subscripts result in an下标超出范围会导致IndexError
.IndexError
。Will be returned by将由len()
.len()
返回。
-
_type_
¶ Specifies the type of each element in the array.指定阵列中每个元素的类型。
Array subclass constructors accept positional arguments, used to initialize the elements in order.数组子类构造函数接受位置参数,用于按顺序初始化元素。-
-
class
ctypes.
_Pointer
¶ P
rivate, abstract base class for pointers.指针的rivate抽象基类。Concrete pointer types are created by calling
POINTER()
with the type that will be pointed to; this is done automatically bypointer()
.If a pointer points to an array, its elements can be read and written using standard subscript and slice accesses.如果指针指向数组,则可以使用标准下标和切片访问来读取和写入其元素。Pointer objects have no size, so指针对象没有大小,因此len()
will raiseTypeError
.len()
将引发TypeError
。Negative subscripts will read from the memory before the pointer (as in C), and out-of-range subscripts will probably crash with an access violation (if you’re lucky).负下标将在指针之前从内存中读取(如C中所示),超出范围的下标可能会因访问冲突而崩溃(如果幸运的话)。-
_type_
¶ Specifies the type pointed to.指定指向的类型。
-
contents
¶ Returns the object to which to pointer points.返回指针指向的对象。Assigning to this attribute changes the pointer to point to the assigned object.指定给该属性会将指针更改为指向指定的对象。
-