ctypes.md
1> **Источник:** https://python-all.ru/3.0/library/ctypes.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# `ctypes` – библиотека для работы с внешними функциями на Python.89`ctypes` – это библиотека для вызова внешних функций из Python. Она предоставляет совместимые с C типы данных и позволяет вызывать функции из DLL или разделяемых библиотек. Её можно использовать для создания обёрток этих библиотек на чистом Python.1011## Руководство по ctypes1213Примечание: примеры кода в этом руководстве используют `doctest`, чтобы убедиться, что они действительно работают. Поскольку некоторые примеры ведут себя по-разному в Linux, Windows и Mac OS X, они содержат директивы doctest в комментариях.1415Примечание: некоторые примеры кода ссылаются на тип ctypes [`c_int`](https://python-all.ru/3.0/library/ctypes.html#ctypes.c_int). Этот тип является псевдонимом для типа [`c_long`](https://python-all.ru/3.0/library/ctypes.html#ctypes.c_long) в 32-битных системах. Так что не стоит путаться, если выводится [`c_long`](https://python-all.ru/3.0/library/ctypes.html#ctypes.c_long), когда вы ожидаете [`c_int`](https://python-all.ru/3.0/library/ctypes.html#ctypes.c_int) – на самом деле это один и тот же тип.1617### Загрузка динамически подключаемых библиотек1819`ctypes` предоставляет объекты *cdll*, а в Windows – *windll* и *oledll* для загрузки динамически подключаемых библиотек.2021Библиотеки загружаются через обращение к ним как к атрибутам этих объектов. *cdll* загружает библиотеки, экспортирующие функции с использованием стандартного соглашения о вызове `cdecl`, тогда как библиотеки *windll* вызывают функции с соглашением `stdcall`. *oledll* также использует соглашение `stdcall` и предполагает, что функции возвращают код ошибки Windows [`HRESULT`](https://python-all.ru/3.0/library/ctypes.html#ctypes.HRESULT). Этот код ошибки используется для автоматического возбуждения исключения `WindowsError` при неудачном вызове функции.2223Вот несколько примеров для Windows. `msvcrt` – это стандартная библиотека C от Microsoft. Она содержит большинство стандартных функций C и использует соглашение о вызовах cdecl.2425```python26>>> from ctypes import *27>>> print(windll.kernel32) # doctest: +WINDOWS28<WinDLL 'kernel32', handle ... at ...>29>>> print(cdll.msvcrt) # doctest: +WINDOWS30<CDLL 'msvcrt', handle ... at ...>31>>> libc = cdll.msvcrt # doctest: +WINDOWS32>>>33```3435Windows автоматически добавляет обычный суффикс файла `.dll`.3637В Linux необходимо указывать имя файла *с расширением* для загрузки библиотеки, поэтому обращение через атрибуты не может использоваться для загрузки библиотек. Следует использовать либо метод `LoadLibrary()` загрузчиков DLL, либо загружать библиотеку, создавая экземпляр CDLL через вызов конструктора:3839```python40>>> cdll.LoadLibrary("libc.so.6") # doctest: +LINUX41<CDLL 'libc.so.6', handle ... at ...>42>>> libc = CDLL("libc.so.6") # doctest: +LINUX43>>> libc # doctest: +LINUX44<CDLL 'libc.so.6', handle ... at ...>45>>>46```4748### Доступ к функциям из загруженных DLL4950Функции доступны как атрибуты объектов DLL:5152```python53>>> from ctypes import *54>>> libc.printf55<_FuncPtr object at 0x...>56>>> print(windll.kernel32.GetModuleHandleA) # doctest: +WINDOWS57<_FuncPtr object at 0x...>58>>> print(windll.kernel32.MyOwnFunction) # doctest: +WINDOWS59Traceback (most recent call last):60 File "<stdin>", line 1, in ?61 File "ctypes.py", line 239, in __getattr__62 func = _StdcallFuncPtr(name, self)63AttributeError: function 'MyOwnFunction' not found64>>>65```6667Обратите внимание, что системные DLL win32, такие как `kernel32` и `user32`, часто экспортируют как ANSI-, так и UNICODE-версии функций. Версия UNICODE экспортируется с добавлением `W` к имени, а версия ANSI – с добавлением `A`. Функция win32 `GetModuleHandle`, которая возвращает *дескриптор модуля* для заданного имени модуля, имеет следующий прототип на C, и макрос используется для предоставления одной из них как `GetModuleHandle` в зависимости от того, определён ли UNICODE:6869```python70/* ANSI version */71HMODULE GetModuleHandleA(LPCSTR lpModuleName);72/* UNICODE version */73HMODULE GetModuleHandleW(LPCWSTR lpModuleName);74```7576*windll* не пытается выбрать одну из них магическим образом – нужно явно указать нужную версию, используя `GetModuleHandleA` или `GetModuleHandleW`, и затем вызывать её, передавая строки или строки Unicode соответственно.7778Иногда DLL экспортируют функции с именами, которые не являются допустимыми идентификаторами Python, например `"??2@YAPAXI@Z"`. В этом случае для получения функции нужно использовать `getattr`:7980```python81>>> getattr(cdll.msvcrt, "??2@YAPAXI@Z") # doctest: +WINDOWS82<_FuncPtr object at 0x...>83>>>84```8586В Windows некоторые DLL экспортируют функции не по имени, а по порядковому номеру. К таким функциям можно получить доступ, индексируя объект DLL по порядковому номеру:8788```python89>>> cdll.kernel32[1] # doctest: +WINDOWS90<_FuncPtr object at 0x...>91>>> cdll.kernel32[0] # doctest: +WINDOWS92Traceback (most recent call last):93 File "<stdin>", line 1, in ?94 File "ctypes.py", line 310, in __getitem__95 func = _StdcallFuncPtr(name, self)96AttributeError: function ordinal 0 not found97>>>98```99100### Вызов функций101102Эти функции можно вызывать как любые другие вызываемые объекты Python. В этом примере используется функция `time()`, возвращающая системное время в секундах с начала эпохи Unix, и функция `GetModuleHandleA()`, возвращающая дескриптор модуля win32.103104В этом примере обе функции вызываются с нулевым указателем (в качестве нулевого указателя следует использовать `None`):105106```python107>>> print(libc.time(None)) # doctest: +SKIP1081150640792109>>> print(hex(windll.kernel32.GetModuleHandleA(None))) # doctest: +WINDOWS1100x1d000000111>>>112```113114`ctypes` пытается защитить от вызова функций с неверным количеством аргументов или неверным соглашением о вызове. К сожалению, это работает только в Windows. Это делается путём проверки стека после возврата функции, так что, хотя и возникает ошибка, функция *была* вызвана:115116```python117>>> windll.kernel32.GetModuleHandleA() # doctest: +WINDOWS118Traceback (most recent call last):119 File "<stdin>", line 1, in ?120ValueError: Procedure probably called with not enough arguments (4 bytes missing)121>>> windll.kernel32.GetModuleHandleA(0, 0) # doctest: +WINDOWS122Traceback (most recent call last):123 File "<stdin>", line 1, in ?124ValueError: Procedure probably called with too many arguments (4 bytes in excess)125>>>126```127128То же исключение возбуждается при вызове функции с соглашением `stdcall` с использованием соглашения о вызове `cdecl`, или наоборот:129130```python131>>> cdll.kernel32.GetModuleHandleA(None) # doctest: +WINDOWS132Traceback (most recent call last):133 File "<stdin>", line 1, in ?134ValueError: Procedure probably called with not enough arguments (4 bytes missing)135>>>136137>>> windll.msvcrt.printf("spam") # doctest: +WINDOWS138Traceback (most recent call last):139 File "<stdin>", line 1, in ?140ValueError: Procedure probably called with too many arguments (4 bytes in excess)141>>>142```143144Чтобы узнать правильное соглашение о вызовах, необходимо заглянуть в C-заголовочный файл или документацию вызываемой функции.145146В Windows `ctypes` использует структурированную обработку исключений Win32 для предотвращения сбоев из-за ошибок защиты общего доступа при вызове функций с недопустимыми значениями аргументов:147148```python149>>> windll.kernel32.GetModuleHandleA(32) # doctest: +WINDOWS150Traceback (most recent call last):151 File "<stdin>", line 1, in ?152WindowsError: exception: access violation reading 0x00000020153>>>154```155156Однако существует достаточно способов привести Python к краху с помощью `ctypes`, так что в любом случае стоит быть внимательным.157158`None`, целые числа, байтовые строки и строки Unicode – единственные собственные объекты Python, которые могут напрямую использоваться в качестве параметров в этих вызовах функций. `None` передаётся как C-указатель `NULL`, байтовые строки и строки Unicode передаются как указатель на блок памяти, содержащий их данные (`char *` или `wchar_t *`). Целые числа Python передаются как тип `int` языка C, принятый на данной платформе, их значение маскируется, чтобы соответствовать C-типу.159160Прежде чем перейти к вызову функций с другими типами параметров, необходимо узнать больше о типах данных `ctypes`.161162### Фундаментальные типы данных163164`ctypes` определяет ряд примитивных типов данных, совместимых с C:165166> | Тип ctypes | Тип C | Тип Python |167> | --- | --- | --- |168> | [`c_char`](https://python-all.ru/3.0/library/ctypes.html#ctypes.c_char) | `char` | односимвольная строка |169> | [`c_wchar`](https://python-all.ru/3.0/library/ctypes.html#ctypes.c_wchar) | `wchar_t` | строка Unicode из одного символа |170> | [`c_byte`](https://python-all.ru/3.0/library/ctypes.html#ctypes.c_byte) | `char` | int |171> | [`c_ubyte`](https://python-all.ru/3.0/library/ctypes.html#ctypes.c_ubyte) | `unsigned char` | int |172> | [`c_short`](https://python-all.ru/3.0/library/ctypes.html#ctypes.c_short) | `short` | int |173> | [`c_ushort`](https://python-all.ru/3.0/library/ctypes.html#ctypes.c_ushort) | `unsigned short` | int |174> | [`c_int`](https://python-all.ru/3.0/library/ctypes.html#ctypes.c_int) | `int` | int |175> | [`c_uint`](https://python-all.ru/3.0/library/ctypes.html#ctypes.c_uint) | `unsigned int` | int |176> | [`c_long`](https://python-all.ru/3.0/library/ctypes.html#ctypes.c_long) | `long` | int |177> | [`c_ulong`](https://python-all.ru/3.0/library/ctypes.html#ctypes.c_ulong) | `unsigned long` | int |178> | [`c_longlong`](https://python-all.ru/3.0/library/ctypes.html#ctypes.c_longlong) | `__int64` или `long long` | int |179> | [`c_ulonglong`](https://python-all.ru/3.0/library/ctypes.html#ctypes.c_ulonglong) | `unsigned __int64` или `unsigned long long` | int |180> | [`c_float`](https://python-all.ru/3.0/library/ctypes.html#ctypes.c_float) | `float` | float |181> | [`c_double`](https://python-all.ru/3.0/library/ctypes.html#ctypes.c_double) | `double` | float |182> | [`c_longdouble`](https://python-all.ru/3.0/library/ctypes.html#ctypes.c_longdouble) | `long double` | float |183> | [`c_char_p`](https://python-all.ru/3.0/library/ctypes.html#ctypes.c_char_p) | `char *` (с завершающим NUL) | строка или `None` |184> | [`c_wchar_p`](https://python-all.ru/3.0/library/ctypes.html#ctypes.c_wchar_p) | `wchar_t *` (с завершающим NUL) | unicode или `None` |185> | [`c_void_p`](https://python-all.ru/3.0/library/ctypes.html#ctypes.c_void_p) | `void *` | int или `None` |186187Все эти типы можно создать, вызвав их с необязательным инициализатором правильного типа и значения:188189```python190>>> c_int()191c_long(0)192>>> c_char_p("Hello, World")193c_char_p('Hello, World')194>>> c_ushort(-3)195c_ushort(65533)196>>>197```198199Поскольку эти типы изменяемы, их значение можно изменить и впоследствии:200201```python202>>> i = c_int(42)203>>> print(i)204c_long(42)205>>> print(i.value)20642207>>> i.value = -99208>>> print(i.value)209-99210>>>211```212213Назначение нового значения экземплярам типов-указателей [`c_char_p`](https://python-all.ru/3.0/library/ctypes.html#ctypes.c_char_p), [`c_wchar_p`](https://python-all.ru/3.0/library/ctypes.html#ctypes.c_wchar_p) и [`c_void_p`](https://python-all.ru/3.0/library/ctypes.html#ctypes.c_void_p) изменяет *адрес памяти*, на который они указывают, *а не содержимое* блока памяти (конечно, нет, потому что строки Python неизменяемы):214215```python216>>> s = "Hello, World"217>>> c_s = c_char_p(s)218>>> print(c_s)219c_char_p('Hello, World')220>>> c_s.value = "Hi, there"221>>> print(c_s)222c_char_p('Hi, there')223>>> print(s) # первая строка не изменяется224Hello, World225>>>226```227228Однако следует быть осторожным и не передавать их функциям, ожидающим указатели на изменяемую память. Если нужны изменяемые блоки памяти, в ctypes есть функция `create_string_buffer`, которая создаёт их разными способами. Текущее содержимое блока памяти можно получить (или изменить) через свойство `raw`; если нужно работать с ним как со строкой, завершающейся NUL, используйте свойство `value`:229230```python231>>> from ctypes import *232>>> p = create_string_buffer(3) # создать буфер размером 3 байта, инициализированный нулевыми байтами233>>> print(sizeof(p), repr(p.raw))2343 '\x00\x00\x00'235>>> p = create_string_buffer("Hello") # создать буфер, содержащий строку, завершающуюся нулевым байтом236>>> print(sizeof(p), repr(p.raw))2376 'Hello\x00'238>>> print(repr(p.value))239'Hello'240>>> p = create_string_buffer("Hello", 10) # создать буфер на 10 байт241>>> print(sizeof(p), repr(p.raw))24210 'Hello\x00\x00\x00\x00\x00'243>>> p.value = "Hi"244>>> print(sizeof(p), repr(p.raw))24510 'Hi\x00lo\x00\x00\x00\x00\x00'246>>>247```248249Функция `create_string_buffer` заменяет функцию `c_buffer` (которая всё ещё доступна как псевдоним), а также функцию `c_string` из более ранних выпусков ctypes. Чтобы создать изменяемый блок памяти, содержащий unicode-символы типа C `wchar_t`, используйте функцию `create_unicode_buffer`.250251### Вызов функций, продолжение252253Обратите внимание, что printf выводит в реальный стандартный поток вывода, *а не* в `sys.stdout`, поэтому эти примеры будут работать только в консоли, а не из среды *IDLE* или *PythonWin*:254255```python256>>> printf = libc.printf257>>> printf("Hello, %s\n", "World!")258Hello, World!25914260>>> printf("Hello, %S", u"World!")261Hello, World!26213263>>> printf("%d bottles of beer\n", 42)26442 bottles of beer26519266>>> printf("%f bottles of beer\n", 42.5)267Traceback (most recent call last):268 File "<stdin>", line 1, in ?269ArgumentError: argument 2: exceptions.TypeError: Don't know how to convert parameter 2270>>>271```272273Как уже упоминалось, все типы Python, кроме целых чисел, строк и unicode-строк, должны быть обёрнуты в соответствующий тип `ctypes`, чтобы их можно было преобразовать в требуемый тип данных C:274275```python276>>> printf("An int %d, a double %f\n", 1234, c_double(3.14))277Integer 1234, double 3.140000104927831279>>>280```281282### Вызов функций с собственными пользовательскими типами данных283284Также можно настроить преобразование аргументов `ctypes`, чтобы экземпляры собственных классов можно было использовать в качестве аргументов функций. `ctypes` ищет атрибут `_as_parameter_` и использует его как аргумент функции. Разумеется, это должно быть целое число, строка или unicode:285286```python287>>> class Bottles(object):288... def __init__(self, number):289... self._as_parameter_ = number290...291>>> bottles = Bottles(42)292>>> printf("%d bottles of beer\n", bottles)29342 bottles of beer29419295>>>296```297298Если не нужно хранить данные экземпляра в переменной экземпляра `_as_parameter_`, можно определить свойство `property`, которое сделает эти данные доступными.299300### Указание требуемых типов аргументов (прототипы функций)301302Можно указать требуемые типы аргументов функций, экспортируемых из DLL, с помощью установки атрибута `argtypes`.303304`argtypes` должен быть последовательностью типов C (функция `printf`, вероятно, не самый удачный пример, потому что она принимает переменное количество параметров разных типов в зависимости от строки формата, но с другой стороны это довольно удобно для экспериментов с этой возможностью):305306```python307>>> printf.argtypes = [c_char_p, c_char_p, c_int, c_double]308>>> printf("String '%s', Int %d, Double %f\n", "Hi", 10, 2.2)309String 'Hi', Int 10, Double 2.20000031037311>>>312```313314Указание формата защищает от несовместимых типов аргументов (как прототип для функции C) и пытается преобразовать аргументы в допустимые типы:315316```python317>>> printf("%d %d %d", 1, 2, 3)318Traceback (most recent call last):319 File "<stdin>", line 1, in ?320ArgumentError: argument 2: exceptions.TypeError: wrong type321>>> printf("%s %d %f", "X", 2, 3)322X 2 3.0000001232312324>>>325```326327Если вы определили собственные классы, экземпляры которых передаются в вызовы функций, необходимо реализовать метод класса `from_param()`, чтобы их можно было использовать в последовательности `argtypes`. Метод класса `from_param()` получает объект Python, переданный в вызов функции; он должен выполнить проверку типа или всё необходимое, чтобы убедиться, что этот объект допустим, а затем вернуть сам объект, его атрибут `_as_parameter_` или то, что вы хотите передать в качестве аргумента функции C в этом случае. Результатом снова должно быть целое число, строка, unicode, экземпляр `ctypes` или объект с атрибутом `_as_parameter_`.328329### Типы возвращаемых значений330331По умолчанию считается, что функции возвращают тип C `int`. Другие возвращаемые типы можно указать, задав атрибут `restype` объекта функции.332333Вот более сложный пример: в нём используется функция `strchr`, которая ожидает указатель на строку и символ (char) и возвращает указатель на строку:334335```python336>>> strchr = libc.strchr337>>> strchr("abcdef", ord("d")) # doctest: +SKIP3388059983339>>> strchr.restype = c_char_p # c_char_p – указатель на строку340>>> strchr("abcdef", ord("d"))341'def'342>>> print(strchr("abcdef", ord("x")))343None344>>>345```346347Если нужно избежать вызовов `ord("x")` выше, можно установить атрибут `argtypes`, и второй аргумент будет преобразован из строки Python из одного символа в C-тип char:348349```python350>>> strchr.restype = c_char_p351>>> strchr.argtypes = [c_char_p, c_char]352>>> strchr("abcdef", "d")353'def'354>>> strchr("abcdef", "def")355Traceback (most recent call last):356 File "<stdin>", line 1, in ?357ArgumentError: argument 2: exceptions.TypeError: one character string expected358>>> print(strchr("abcdef", "x"))359None360>>> strchr("abcdef", "d")361'def'362>>>363```364365Также можно использовать вызываемый объект Python (например, функцию или класс) в качестве атрибута `restype`, если внешняя функция возвращает целое число. Вызываемый объект будет вызван с `целым числом`, которое вернула C-функция, а результат этого вызова будет использован как результат вашего вызова функции. Это полезно для проверки возвращаемых значений на ошибки и автоматического возбуждения исключения:366367```python368>>> GetModuleHandle = windll.kernel32.GetModuleHandleA # doctest: +WINDOWS369>>> def ValidHandle(value):370... if value == 0:371... raise WinError()372... return value373...374>>>375>>> GetModuleHandle.restype = ValidHandle # doctest: +WINDOWS376>>> GetModuleHandle(None) # doctest: +WINDOWS377486539264378>>> GetModuleHandle("something silly") # doctest: +WINDOWS379Traceback (most recent call last):380 File "<stdin>", line 1, in ?381 File "<stdin>", line 3, in ValidHandle382WindowsError: [Errno 126] The specified module could not be found.383>>>384```385386`WinError` – это функция, которая вызывает Windows API `FormatMessage()` для получения строкового представления кода ошибки и *возвращает* исключение. `WinError` принимает необязательный параметр – код ошибки; если он не передан, функция вызывает [`GetLastError()`](https://python-all.ru/3.0/library/ctypes.html#ctypes.GetLastError) для его получения.387388Обратите внимание, что гораздо более мощный механизм проверки ошибок доступен через атрибут `errcheck`; подробности см. в справочном руководстве.389390### Передача указателей (или: передача параметров по ссылке)391392Иногда функция C API ожидает в качестве параметра *указатель* на тип данных, обычно для записи в соответствующее место или если данные слишком велики для передачи по значению. Это также называется *передачей параметров по ссылке*.393394`ctypes` экспортирует функцию [`byref()`](https://python-all.ru/3.0/library/ctypes.html#ctypes.byref), которая используется для передачи параметров по ссылке. Того же эффекта можно достичь с помощью функции `pointer`, хотя `pointer` выполняет гораздо больше работы, так как создаёт настоящий объект-указатель, поэтому быстрее использовать [`byref()`](https://python-all.ru/3.0/library/ctypes.html#ctypes.byref), если объект-указатель не нужен в самом Python:395396```python397>>> i = c_int()398>>> f = c_float()399>>> s = create_string_buffer('\000' * 32)400>>> print(i.value, f.value, repr(s.value))4010 0.0 ''402>>> libc.sscanf("1 3.14 Hello", "%d %f %s",403... byref(i), byref(f), s)4043405>>> print(i.value, f.value, repr(s.value))4061 3.1400001049 'Hello'407>>>408```409410### Структуры и объединения411412Структуры и объединения должны быть производными от базовых классов [`Structure`](https://python-all.ru/3.0/library/ctypes.html#ctypes.Structure) и [`Union`](https://python-all.ru/3.0/library/ctypes.html#ctypes.Union), которые определены в модуле `ctypes`. Каждый подкласс должен определить атрибут `_fields_`. `_fields_` должен быть списком из *2-кортежей*, содержащих *имя поля* и *тип поля*.413414Тип поля должен быть типом `ctypes`, например [`c_int`](https://python-all.ru/3.0/library/ctypes.html#ctypes.c_int), или любым другим производным типом `ctypes`: структура, объединение, массив, указатель.415416Вот простой пример структуры POINT, которая содержит два целых числа с именами `x` и `y`, а также показывает, как инициализировать структуру в конструкторе:417418```python419>>> from ctypes import *420>>> class POINT(Structure):421... _fields_ = [("x", c_int),422... ("y", c_int)]423...424>>> point = POINT(10, 20)425>>> print(point.x, point.y)42610 20427>>> point = POINT(y=5)428>>> print(point.x, point.y)4290 5430>>> POINT(1, 2, 3)431Traceback (most recent call last):432 File "<stdin>", line 1, in ?433ValueError: too many initializers434>>>435```436437Однако можно создавать гораздо более сложные структуры. Структуры могут сами содержать другие структуры, используя структуру в качестве типа поля.438439Вот структура RECT, которая содержит две точки POINT с именами `upperleft` и `lowerright`440441```python442>>> class RECT(Structure):443... _fields_ = [("upperleft", POINT),444... ("lowerright", POINT)]445...446>>> rc = RECT(point)447>>> print(rc.upperleft.x, rc.upperleft.y)4480 5449>>> print(rc.lowerright.x, rc.lowerright.y)4500 0451>>>452```453454Вложенные структуры также можно инициализировать в конструкторе несколькими способами:455456```python457>>> r = RECT(POINT(1, 2), POINT(3, 4))458>>> r = RECT((1, 2), (3, 4))459```460461полей [*descriptor*](https://python-all.ru/3.0/glossary.html#term-descriptor) можно получить из *класса*; они полезны для отладки, так как предоставляют полезную информацию:462463```python464>>> print(POINT.x)465<Field type=c_long, ofs=0, size=4>466>>> print(POINT.y)467<Field type=c_long, ofs=4, size=4>468>>>469```470471### Выравнивание структур/объединений и порядок байтов472473По умолчанию поля Structure и Union выравниваются так же, как это делает компилятор C. Можно переопределить это поведение, указав атрибут класса `_pack_` в определении подкласса. Он должен быть установлен в положительное целое число и задает максимальное выравнивание для полей. Это то же самое, что делает `#pragma pack(n)` в MSVC.474475`ctypes` использует собственный порядок байтов для структур и объединений. Чтобы создать структуры с нестандартным порядком байтов, можно использовать один из базовых классов: BigEndianStructure, LittleEndianStructure, BigEndianUnion и LittleEndianUnion. Эти классы не могут содержать поля-указатели.476477### Битовые поля в структурах и объединениях478479Можно создавать структуры и объединения, содержащие битовые поля. Битовые поля возможны только для целочисленных полей; ширина битового поля задается третьим элементом в кортежах `_fields_`:480481```python482>>> class Int(Structure):483... _fields_ = [("first_16", c_int, 16),484... ("second_16", c_int, 16)]485...486>>> print(Int.first_16)487<Field type=c_long, ofs=0:0, bits=16>488>>> print(Int.second_16)489<Field type=c_long, ofs=0:16, bits=16>490>>>491```492493### Массивы494495Массивы – это последовательности, содержащие фиксированное количество экземпляров одного типа.496497Рекомендуемый способ создания типов массивов – умножение типа данных на положительное целое число:498499```python500TenPointsArrayType = POINT * 10501```502503Вот пример несколько искусственного типа данных – структуры, содержащей 4 точки POINT среди прочего:504505```python506>>> from ctypes import *507>>> class POINT(Structure):508... _fields_ = ("x", c_int), ("y", c_int)509...510>>> class MyStruct(Structure):511... _fields_ = [("a", c_int),512... ("b", c_float),513... ("point_array", POINT * 4)]514>>>515>>> print(len(MyStruct().point_array))5164517>>>518```519520Экземпляры создаются обычным способом – вызовом класса:521522```python523arr = TenPointsArrayType()524for pt in arr:525 print(pt.x, pt.y)526```527528Приведенный выше код выводит серию строк `0 0`, потому что содержимое массива инициализируется нулями.529530Можно также указать инициализаторы правильного типа:531532```python533>>> from ctypes import *534>>> TenIntegers = c_int * 10535>>> ii = TenIntegers(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)536>>> print(ii)537<c_long_Array_10 object at 0x...>538>>> for i in ii: print(i, end=" ")539...5401 2 3 4 5 6 7 8 9 10541>>>542```543544### Указатели545546Экземпляры указателей создаются вызовом функции `pointer` для типа `ctypes`:547548```python549>>> from ctypes import *550>>> i = c_int(42)551>>> pi = pointer(i)552>>>553```554555Экземпляры указателей имеют атрибут `contents`, который возвращает объект, на который указывает указатель – объект `i` из примера выше:556557```python558>>> pi.contents559c_long(42)560>>>561```562563Обратите внимание, что `ctypes` не поддерживает OOR (возврат исходного объекта), он создаёт новый эквивалентный объект каждый раз при получении атрибута:564565```python566>>> pi.contents is i567False568>>> pi.contents is pi.contents569False570>>>571```572573Присвоение другого экземпляра [`c_int`](https://python-all.ru/3.0/library/ctypes.html#ctypes.c_int) атрибуту contents указателя приведет к тому, что указатель будет указывать на область памяти, где этот экземпляр хранится:574575```python576>>> i = c_int(99)577>>> pi.contents = i578>>> pi.contents579c_long(99)580>>>581```582583Экземпляры указателей также можно индексировать целыми числами:584585```python586>>> pi[0]58799588>>>589```590591Присваивание целочисленному индексу изменяет значение, на которое указывает указатель:592593```python594>>> print(i)595c_long(99)596>>> pi[0] = 22597>>> print(i)598c_long(22)599>>>600```601602It 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. 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.603604Под капотом функция `pointer` делает больше, чем просто создаёт экземпляры указателей: сначала она должна создать типы *указателей*. Это делается с помощью функции `POINTER`, которая принимает любой тип `ctypes` и возвращает новый тип:605606```python607>>> PI = POINTER(c_int)608>>> PI609<class 'ctypes.LP_c_long'>610>>> PI(42)611Traceback (most recent call last):612 File "<stdin>", line 1, in ?613TypeError: expected c_long instead of int614>>> PI(c_int(42))615<ctypes.LP_c_long object at 0x...>616>>>617```618619Вызов типа указателя без аргумента создает нулевой указатель `NULL`. Нулевые указатели `NULL` имеют булево значение `False`:620621```python622>>> null_ptr = POINTER(c_int)()623>>> print(bool(null_ptr))624False625>>>626```627628`ctypes` проверяет на `NULL` при разыменовании указателей (но разыменование недопустимых указателей, отличных от `NULL`, приведёт к аварийному завершению Python):629630```python631>>> null_ptr[0]632Traceback (most recent call last):633 ....634ValueError: NULL pointer access635>>>636637>>> null_ptr[0] = 1234638Traceback (most recent call last):639 ....640ValueError: NULL pointer access641>>>642```643644### Преобразования типов645646Обычно ctypes выполняет строгую проверку типов. Это означает, что если у вас есть `POINTER(c_int)` в списке `argtypes` функции или в качестве типа поля-члена в определении структуры, принимаются только экземпляры точно того же типа. Из этого правила есть некоторые исключения, когда ctypes принимает другие объекты. Например, можно передавать совместимые экземпляры массивов вместо типов указателей. Так, для `POINTER(c_int)` ctypes принимает массив c\_int:647648```python649>>> class Bar(Structure):650... _fields_ = [("count", c_int), ("values", POINTER(c_int))]651...652>>> bar = Bar()653>>> bar.values = (c_int * 3)(1, 2, 3)654>>> bar.count = 3655>>> for i in range(bar.count):656... print(bar.values[i])657...658165926603661>>>662```663664Чтобы установить поле типа POINTER в `NULL`, можно присвоить `None`:665666```python667>>> bar.values = None668>>>669```670671Иногда встречаются экземпляры несовместимых типов. В C можно привести один тип к другому. `ctypes` предоставляет функцию `cast`, которую можно использовать так же. Определённая выше структура `Bar` принимает указатели `POINTER(c_int)` или массивы [`c_int`](https://python-all.ru/3.0/library/ctypes.html#ctypes.c_int) для своего поля `values`, но не экземпляры других типов:672673```python674>>> bar.values = (c_byte * 4)()675Traceback (most recent call last):676 File "<stdin>", line 1, in ?677TypeError: incompatible types, c_byte_Array_4 instance instead of LP_c_long instance678>>>679```680681Для таких случаев функция `cast` удобна.682683Функция `cast` используется для приведения экземпляра ctypes к указателю на другой тип данных ctypes. `cast` принимает два параметра: объект ctypes, который является указателем или может быть преобразован в указатель некоторого типа, и тип указателя ctypes. Она возвращает экземпляр второго аргумента, который ссылается на тот же блок памяти, что и первый аргумент:684685```python686>>> a = (c_byte * 4)()687>>> cast(a, POINTER(c_int))688<ctypes.LP_c_long object at ...>689>>>690```691692Таким образом, `cast` можно использовать для присваивания полю `values` структуры `Bar`:693694```python695>>> bar = Bar()696>>> bar.values = cast((c_byte * 4)(), POINTER(c_int))697>>> print(bar.values[0])6980699>>>700```701702### Неполные типы703704*Неполные типы* – это структуры, объединения или массивы, члены которых ещё не определены. В C они задаются опережающими объявлениями, которые определяются позже:705706```python707struct cell; /* forward declaration */708709struct {710 char *name;711 struct cell *next;712} cell;713```714715Прямой перевод в код ctypes выглядел бы так, но это не работает:716717```python718>>> class cell(Structure):719... _fields_ = [("name", c_char_p),720... ("next", POINTER(cell))]721...722Traceback (most recent call last):723 File "<stdin>", line 1, in ?724 File "<stdin>", line 2, in cell725NameError: name 'cell' is not defined726>>>727```728729поскольку новый `класс cell` недоступен в самом операторе class. В `ctypes` можно определить класс `cell` и задать атрибут `_fields_` позже, после оператора class:730731```python732>>> from ctypes import *733>>> class cell(Structure):734... pass735...736>>> cell._fields_ = [("name", c_char_p),737... ("next", POINTER(cell))]738>>>739```740741Попробуем. Создадим два экземпляра `cell`, заставим их указывать друг на друга и, наконец, пройдем по цепочке указателей несколько раз:742743```python744>>> c1 = cell()745>>> c1.name = "foo"746>>> c2 = cell()747>>> c2.name = "bar"748>>> c1.next = pointer(c2)749>>> c2.next = pointer(c1)750>>> p = c1751>>> for i in range(8):752... print(p.name, end=" ")753... p = p.next[0]754...755foo bar foo bar foo bar foo bar756>>>757```758759### Функции обратного вызова760761`ctypes` позволяет создавать указатели на функции C из вызываемых объектов Python. Их иногда называют *функциями обратного вызова*.762763Сначала необходимо создать класс для функции обратного вызова. Этот класс знает соглашение вызова, тип возвращаемого значения, а также количество и типы аргументов, которые будет получать эта функция.764765Фабричная функция CFUNCTYPE создаёт типы для функций обратного вызова с использованием обычного соглашения вызова cdecl, а на Windows фабричная функция WINFUNCTYPE создаёт типы для функций обратного вызова с использованием соглашения вызова stdcall.766767Обе эти фабричные функции вызываются с типом результата в качестве первого аргумента, а ожидаемые типы аргументов функции обратного вызова передаются как остальные аргументы.768769Здесь будет приведён пример, использующий функцию `qsort()` из стандартной библиотеки C. Она сортирует элементы с помощью функции обратного вызова. `qsort()` будет использована для сортировки массива целых чисел:770771```python772>>> IntArray5 = c_int * 5773>>> ia = IntArray5(5, 1, 7, 33, 99)774>>> qsort = libc.qsort775>>> qsort.restype = None776>>>777```778779Функция `qsort()` должна вызываться с указателем на данные для сортировки, количеством элементов в массиве данных, размером одного элемента и указателем на функцию сравнения (обратный вызов). Затем обратный вызов будет вызван с двумя указателями на элементы; он должен возвращать отрицательное целое число, если первый элемент меньше второго, ноль, если они равны, и положительное целое число в противном случае.780781Итак, наша функция обратного вызова получает указатели на целые числа и должна возвращать целое число. Сначала создадим `тип` для функции обратного вызова:782783```python784>>> CMPFUNC = CFUNCTYPE(c_int, POINTER(c_int), POINTER(c_int))785>>>786```787788Для первой реализации функции обратного вызова мы просто выводим полученные аргументы и возвращаем 0 (итеративная разработка ;-)):789790```python791>>> def py_cmp_func(a, b):792... print("py_cmp_func", a, b)793... return 0794...795>>>796```797798Создайте вызываемый из C обратный вызов:799800```python801>>> cmp_func = CMPFUNC(py_cmp_func)802>>>803```804805И мы готовы начать:806807```python808>>> qsort(ia, len(ia), sizeof(c_int), cmp_func) # doctest: +WINDOWS809py_cmp_func <ctypes.LP_c_long object at 0x00...> <ctypes.LP_c_long object at 0x00...>810py_cmp_func <ctypes.LP_c_long object at 0x00...> <ctypes.LP_c_long object at 0x00...>811py_cmp_func <ctypes.LP_c_long object at 0x00...> <ctypes.LP_c_long object at 0x00...>812py_cmp_func <ctypes.LP_c_long object at 0x00...> <ctypes.LP_c_long object at 0x00...>813py_cmp_func <ctypes.LP_c_long object at 0x00...> <ctypes.LP_c_long object at 0x00...>814py_cmp_func <ctypes.LP_c_long object at 0x00...> <ctypes.LP_c_long object at 0x00...>815py_cmp_func <ctypes.LP_c_long object at 0x00...> <ctypes.LP_c_long object at 0x00...>816py_cmp_func <ctypes.LP_c_long object at 0x00...> <ctypes.LP_c_long object at 0x00...>817py_cmp_func <ctypes.LP_c_long object at 0x00...> <ctypes.LP_c_long object at 0x00...>818py_cmp_func <ctypes.LP_c_long object at 0x00...> <ctypes.LP_c_long object at 0x00...>819>>>820```821822Мы знаем, как получить доступ к содержимому указателя, поэтому переопределим наш колбэк:823824```python825>>> def py_cmp_func(a, b):826... print("py_cmp_func", a[0], b[0])827... return 0828...829>>> cmp_func = CMPFUNC(py_cmp_func)830>>>831```832833Вот что мы получаем в Windows:834835```python836>>> qsort(ia, len(ia), sizeof(c_int), cmp_func) # doctest: +WINDOWS837py_cmp_func 7 1838py_cmp_func 33 1839py_cmp_func 99 1840py_cmp_func 5 1841py_cmp_func 7 5842py_cmp_func 33 5843py_cmp_func 99 5844py_cmp_func 7 99845py_cmp_func 33 99846py_cmp_func 7 33847>>>848```849850Забавно, что в Linux функция сортировки работает гораздо эффективнее: она делает меньше сравнений:851852```python853>>> qsort(ia, len(ia), sizeof(c_int), cmp_func) # doctest: +LINUX854py_cmp_func 5 1855py_cmp_func 33 99856py_cmp_func 7 33857py_cmp_func 5 7858py_cmp_func 1 7859>>>860```861862Ах, мы почти закончили! Последний шаг – собственно сравнить два элемента и вернуть полезный результат:863864```python865>>> def py_cmp_func(a, b):866... print("py_cmp_func", a[0], b[0])867... return a[0] - b[0]868...869>>>870```871872Финальный запуск в Windows:873874```python875>>> qsort(ia, len(ia), sizeof(c_int), CMPFUNC(py_cmp_func)) # doctest: +WINDOWS876py_cmp_func 33 7877py_cmp_func 99 33878py_cmp_func 5 99879py_cmp_func 1 99880py_cmp_func 33 7881py_cmp_func 1 33882py_cmp_func 5 33883py_cmp_func 5 7884py_cmp_func 1 7885py_cmp_func 5 1886>>>887```888889и в Linux:890891```python892>>> qsort(ia, len(ia), sizeof(c_int), CMPFUNC(py_cmp_func)) # doctest: +LINUX893py_cmp_func 5 1894py_cmp_func 33 99895py_cmp_func 7 33896py_cmp_func 1 7897py_cmp_func 5 7898>>>899```900901Довольно интересно, что функция `qsort()` в Windows требует больше сравнений, чем версия в linux!902903Как легко проверить, наш массив теперь отсортирован:904905```python906>>> for i in ia: print(i, end=" ")907...9081 5 7 33 99909>>>910```911912**Важное замечание для функций обратного вызова:**913914Убедитесь, что вы храните ссылки на объекты CFUNCTYPE, пока они используются из кода C. `ctypes` этого не делает, и если не хранить, они могут быть собраны сборщиком мусора, что приведёт к аварийному завершению программы при вызове колбэка.915916### Доступ к значениям, экспортируемым из DLL917918Некоторые разделяемые библиотеки экспортируют не только функции, но и переменные. Примером в самой библиотеке Python является `Py_OptimizeFlag` – целое число, устанавливаемое в 0, 1 или 2 в зависимости от флага [*-O*](https://python-all.ru/3.0/using/cmdline.html#cmdoption-O) или [*-OO*](https://python-all.ru/3.0/using/cmdline.html#cmdoption-OO), переданного при запуске.919920`ctypes` может получать доступ к значениям подобным образом с помощью методов класса `in_dll()` типа. *pythonapi* – это предопределённый символ, предоставляющий доступ к C API Python:921922```python923>>> opt_flag = c_int.in_dll(pythonapi, "Py_OptimizeFlag")924>>> print(opt_flag)925c_long(0)926>>>927```928929Если бы интерпретатор был запущен с флагом [*-O*](https://python-all.ru/3.0/using/cmdline.html#cmdoption-O), пример вывел бы `c_long(1)`, или `c_long(2)`, если бы был указан [*-OO*](https://python-all.ru/3.0/using/cmdline.html#cmdoption-OO).930931Расширенный пример, который также демонстрирует использование указателей для доступа к указателю `PyImport_FrozenModules`, экспортируемому Python.932933Цитируя документацию Python: *Этот указатель инициализируется так, чтобы указывать на массив записей «struct \_frozen», завершающийся записью, все члены которой равны NULL или нулю. При импорте замороженного модуля он ищется в этой таблице. Сторонний код может использовать это для динамического создания набора замороженных модулей.*934935Таким образом, манипуляции с этим указателем могут даже оказаться полезными. Чтобы ограничить размер примера, мы покажем только, как эту таблицу можно прочитать с помощью `ctypes`:936937```python938>>> from ctypes import *939>>>940>>> class struct_frozen(Structure):941... _fields_ = [("name", c_char_p),942... ("code", POINTER(c_ubyte)),943... ("size", c_int)]944...945>>>946```947948Мы определили тип данных `struct _frozen`, поэтому можем получить указатель на таблицу:949950```python951>>> FrozenTable = POINTER(struct_frozen)952>>> table = FrozenTable.in_dll(pythonapi, "PyImport_FrozenModules")953>>>954```955956Поскольку `table` – это `указатель` на массив записей `struct_frozen`, мы можем выполнять итерацию по нему, но нужно убедиться, что цикл завершится, ведь у указателей нет размера. Рано или поздно это, вероятно, приведёт к ошибке доступа или чему-то подобному, так что лучше выйти из цикла, когда мы достигнем NULL-записи:957958```python959>>> for item in table:960... print(item.name, item.size)961... if item.name is None:962... break963...964__hello__ 104965__phello__ -104966__phello__.spam 104967None 0968>>>969```970971То, что в стандартном Python есть frozen-модуль и frozen-пакет (обозначаемый отрицательным значением поля size), малоизвестно; это используется только для тестирования. Попробуйте, например, `import __hello__`.972973### Неожиданности974975В `ctypes` есть некоторые пограничные случаи, когда поведение может отличаться от ожидаемого.976977Рассмотрим следующий пример:978979```python980>>> from ctypes import *981>>> class POINT(Structure):982... _fields_ = ("x", c_int), ("y", c_int)983...984>>> class RECT(Structure):985... _fields_ = ("a", POINT), ("b", POINT)986...987>>> p1 = POINT(1, 2)988>>> p2 = POINT(3, 4)989>>> rc = RECT(p1, p2)990>>> print(rc.a.x, rc.a.y, rc.b.x, rc.b.y)9911 2 3 4992>>> # теперь поменять точки местами993>>> rc.a, rc.b = rc.b, rc.a994>>> print(rc.a.x, rc.a.y, rc.b.x, rc.b.y)9953 4 3 4996>>>997```998999Хм. Мы, конечно, ожидали, что последний оператор выведет `3 4 1 2`. Что произошло? Вот шаги строки `rc.a, rc.b = rc.b, rc.a` выше:10001001```python1002>>> temp0, temp1 = rc.b, rc.a1003>>> rc.a = temp01004>>> rc.b = temp11005>>>1006```10071008Обратите внимание, что `temp0` и `temp1` – это объекты, всё ещё использующие внутренний буфер объекта `rc` выше. Таким образом, выполнение `rc.a = temp0` копирует содержимое буфера `temp0` в буфер `rc`. Это, в свою очередь, изменяет содержимое `temp1`. Поэтому последнее присваивание `rc.b = temp1` не даёт ожидаемого эффекта.10091010Имейте в виду, что получение подобъектов из Structure, Unions и Arrays не *копирует* подобъект, а возвращает объект-обертку, обращающийся к базовому буферу корневого объекта.10111012Еще один пример, который может вести себя не так, как ожидается:10131014```python1015>>> s = c_char_p()1016>>> s.value = "abc def ghi"1017>>> s.value1018'abc def ghi'1019>>> s.value is s.value1020False1021>>>1022```10231024Почему выводится `False`? Экземпляры ctypes – это объекты, содержащие блок памяти и несколько [*дескрипторов*](https://python-all.ru/3.0/glossary.html#term-descriptor) для доступа к содержимому памяти. При сохранении объекта Python в блоке памяти сохраняется не сам объект, а его `содержимое`. При каждом обращении к содержимому создаётся новый объект Python!10251026### Типы данных переменного размера10271028`ctypes` предоставляет некоторую поддержку массивов и структур переменного размера (эта возможность добавлена в версии 0.9.9.7).10291030Функция `resize` используется для изменения размера буфера памяти существующего объекта ctypes. Она принимает объект в качестве первого аргумента и запрашиваемый размер в байтах в качестве второго. Блок памяти нельзя сделать меньше естественного блока, задаваемого типом объекта; при попытке этого возникает исключение `ValueError`:10311032```python1033>>> short_array = (c_short * 4)()1034>>> print(sizeof(short_array))103581036>>> resize(short_array, 4)1037Traceback (most recent call last):1038 ...1039ValueError: minimum size is 81040>>> resize(short_array, 32)1041>>> sizeof(short_array)1042321043>>> sizeof(type(short_array))104481045>>>1046```10471048Это хорошо и замечательно, но как получить доступ к дополнительным элементам, содержащимся в этом массиве? Поскольку тип по-прежнему знает только о 4 элементах, при попытке доступа к другим элементам возникают ошибки:10491050```python1051>>> short_array[:]1052[0, 0, 0, 0]1053>>> short_array[7]1054Traceback (most recent call last):1055 ...1056IndexError: invalid index1057>>>1058```10591060Другой способ использования типов данных переменного размера с `ctypes` – это воспользоваться динамической природой Python и (пере)определять тип данных после того, как необходимый размер уже известен, для каждого конкретного случая.10611062## Справочник по ctypes10631064### Поиск разделяемых библиотек10651066При программировании на компилируемом языке к разделяемым библиотекам обращаются при компиляции/компоновке программы и при ее запуске.10671068Назначение функции `find_library` – найти библиотеку способом, аналогичным тому, что делает компилятор (на платформах с несколькими версиями разделяемой библиотеки должна загружаться самая новая), в то время как загрузчики библиотек ctypes действуют как при запуске программы и вызывают загрузчик времени выполнения напрямую.10691070Модуль `ctypes.util` предоставляет функцию, которая может помочь определить, какую библиотеку загружать.10711072#### `ctypes.util.find_library(name)`10731074Пытается найти библиотеку и возвращает путь к ней.10751076*name*10771078– это имя библиотеки без префикса10791080*lib*10811082, суффикса10831084`.so`10851086,10871088`.dylib`10891090или номера версии (именно такая форма используется для опции компоновщика posix10911092*-l*10931094). Если библиотеку не удалось найти, возвращает10951096`None`10971098.10991100Точное поведение зависит от системы.11011102В Linux `find_library` пытается запустить внешние программы (/sbin/ldconfig, gcc и objdump), чтобы найти файл библиотеки. Она возвращает имя файла библиотеки. Вот несколько примеров:11031104```python1105>>> from ctypes.util import find_library1106>>> find_library("m")1107'libm.so.6'1108>>> find_library("c")1109'libc.so.6'1110>>> find_library("bz2")1111'libbz2.so.1.0'1112>>>1113```11141115В OS X `find_library` перебирает несколько предопределённых схем именования и путей для поиска библиотеки и возвращает полный путь в случае успеха:11161117```python1118>>> from ctypes.util import find_library1119>>> find_library("c")1120'/usr/lib/libc.dylib'1121>>> find_library("m")1122'/usr/lib/libm.dylib'1123>>> find_library("bz2")1124'/usr/lib/libbz2.dylib'1125>>> find_library("AGL")1126'/System/Library/Frameworks/AGL.framework/AGL'1127>>>1128```11291130В Windows `find_library` ищет по системному пути поиска и возвращает полное имя файла, но из-за отсутствия предопределённой схемы именования вызов вроде `find_library("c")` завершится ошибкой и вернёт `None`.11311132При обёртывании разделяемой библиотеки с помощью `ctypes`, *возможно*, лучше определить имя разделяемой библиотеки на этапе разработки и жёстко прописать его в модуле-обёртке, вместо использования `find_library` для поиска библиотеки во время выполнения.11331134### Загрузка динамических библиотек11351136Существует несколько способов загрузить разделяемые библиотеки в процесс Python. Один из способов – создать экземпляр одного из следующих классов:11371138#### `[ctypes.CDLL]class ctypes.CDLL(name, mode=DEFAULT_MODE, handle=None, use_errno=False, use_last_error=False)`11391140Экземпляры этого класса представляют загруженные разделяемые библиотеки. Функции в этих библиотеках используют стандартное соглашение о вызове C и считаются возвращающими11411142`int`11431144.11451146#### `[ctypes.OleDLL]class ctypes.OleDLL(name, mode=DEFAULT_MODE, handle=None, use_errno=False, use_last_error=False)`11471148Только для Windows: экземпляры этого класса представляют загруженные разделяемые библиотеки, функции в этих библиотеках используют соглашение о вызовах11491150`stdcall`11511152и, как предполагается, возвращают специфичный для Windows код11531154[`HRESULT`](https://python-all.ru/3.0/library/ctypes.html#ctypes.HRESULT)11551156. Значения11571158[`HRESULT`](https://python-all.ru/3.0/library/ctypes.html#ctypes.HRESULT)11591160содержат информацию, указывающую, завершился ли вызов функции неудачей или успехом, вместе с дополнительным кодом ошибки. Если возвращаемое значение сигнализирует об ошибке, автоматически вызывается исключение11611162`WindowsError`11631164.11651166#### `[ctypes.WinDLL]class ctypes.WinDLL(name, mode=DEFAULT_MODE, handle=None, use_errno=False, use_last_error=False)`11671168Только для Windows: экземпляры этого класса представляют загруженные разделяемые библиотеки, функции в этих библиотеках используют соглашение о вызове `stdcall` и по умолчанию предполагается, что они возвращают `int`.11691170На Windows CE используется только стандартное соглашение о вызове; для удобства [`WinDLL`](https://python-all.ru/3.0/library/ctypes.html#ctypes.WinDLL) и [`OleDLL`](https://python-all.ru/3.0/library/ctypes.html#ctypes.OleDLL) на этой платформе используют стандартное соглашение о вызове.11711172Глобальная блокировка интерпретатора Python [*global interpreter lock*](https://python-all.ru/3.0/glossary.html#term-global-interpreter-lock) освобождается перед вызовом любой функции, экспортируемой этими библиотеками, и снова захватывается после вызова.11731174#### `[ctypes.PyDLL]class ctypes.PyDLL(name, mode=DEFAULT_MODE, handle=None)`11751176Экземпляры этого класса ведут себя как экземпляры [`CDLL`](https://python-all.ru/3.0/library/ctypes.html#ctypes.CDLL), за исключением того, что GIL Python *не* освобождается при вызове функции, а после выполнения функции проверяется флаг ошибок Python. Если флаг ошибок установлен, возбуждается исключение Python.11771178Таким образом, это полезно только для прямого вызова функций Python C API.11791180Все эти классы могут быть созданы вызовом с как минимум одним аргументом – путём к разделяемой библиотеке. Если у вас уже есть дескриптор загруженной разделяемой библиотеки, его можно передать как именованный параметр `handle`; в противном случае используется функция базовой платформы `dlopen` или `LoadLibrary()` для загрузки библиотеки в процесс и получения её дескриптора.11811182Параметр *mode* используется для указания способа загрузки библиотеки. Подробнее см. man-страницу `dlopen(3)`; в Windows параметр *mode* игнорируется.11831184Параметр *use\_errno* при установке в True включает механизм ctypes, который позволяет безопасно получать доступ к системному коду ошибки `errno`. `ctypes` хранит потоко-локальную копию системной переменной `errno`; если вызвать внешние функции, созданные с `use_errno=True`, то значение `errno` перед вызовом функции заменяется на приватную копию ctypes, и то же самое происходит сразу после вызова функции.11851186Функция [`ctypes.get_errno()`](https://python-all.ru/3.0/library/ctypes.html#ctypes.get_errno) возвращает значение частной копии ctypes, а функция [`ctypes.set_errno()`](https://python-all.ru/3.0/library/ctypes.html#ctypes.set_errno) изменяет частную копию ctypes на новое значение и возвращает предыдущее значение.11871188Параметр *use\_last\_error*, если установлен в True, включает тот же механизм для кода ошибки Windows, который управляется функциями Windows API [`GetLastError()`](https://python-all.ru/3.0/library/ctypes.html#ctypes.GetLastError) и `SetLastError()`; функции [`ctypes.get_last_error()`](https://python-all.ru/3.0/library/ctypes.html#ctypes.get_last_error) и [`ctypes.set_last_error()`](https://python-all.ru/3.0/library/ctypes.html#ctypes.set_last_error) используются для получения и изменения частной копии кода ошибки Windows в ctypes.11891190#### `ctypes.RTLD_GLOBAL`11911192Флаг, используемый в качестве параметра11931194*mode*11951196. На платформах, где этот флаг недоступен, он определён как целочисленный ноль.11971198#### `ctypes.RTLD_LOCAL`11991200Флаг, используемый в качестве параметра12011202*mode*12031204. На платформах, где он недоступен, он совпадает с12051206*RTLD\_GLOBAL*12071208.12091210#### `ctypes.DEFAULT_MODE`12111212Режим по умолчанию, используемый для загрузки разделяемых библиотек. На OSX 10.3 это12131214*RTLD\_GLOBAL*12151216, в противном случае он совпадает с12171218*RTLD\_LOCAL*12191220.12211222Экземпляры этих классов не имеют открытых методов, однако [`__getattr__()`](https://python-all.ru/3.0/reference/datamodel.html#object.__getattr__) и [`__getitem__()`](https://python-all.ru/3.0/reference/datamodel.html#object.__getitem__) обладают особым поведением: функции, экспортируемые общей библиотекой, могут быть доступны как атрибуты или по индексу. Обратите внимание, что оба [`__getattr__()`](https://python-all.ru/3.0/reference/datamodel.html#object.__getattr__) и [`__getitem__()`](https://python-all.ru/3.0/reference/datamodel.html#object.__getitem__) кешируют свой результат, поэтому повторные вызовы возвращают один и тот же объект.12231224Доступны следующие открытые атрибуты, их имена начинаются с подчёркивания, чтобы не конфликтовать с именами экспортируемых функций:12251226#### `[ctypes.PyDLL._handle]PyDLL._handle`12271228Системный дескриптор, используемый для доступа к библиотеке.12291230#### `[ctypes.PyDLL._name]PyDLL._name`12311232Имя библиотеки, переданное в конструктор.12331234Разделяемые библиотеки также можно загружать с помощью одного из предварительно созданных объектов, которые являются экземплярами класса [`LibraryLoader`](https://python-all.ru/3.0/library/ctypes.html#ctypes.LibraryLoader), либо вызывая метод `LoadLibrary()`, либо получая библиотеку как атрибут экземпляра загрузчика.12351236#### `[ctypes.LibraryLoader]class ctypes.LibraryLoader(dlltype)`12371238Класс, который загружает разделяемые библиотеки. `dlltype` должен быть одним из типов [`CDLL`](https://python-all.ru/3.0/library/ctypes.html#ctypes.CDLL), [`PyDLL`](https://python-all.ru/3.0/library/ctypes.html#ctypes.PyDLL), [`WinDLL`](https://python-all.ru/3.0/library/ctypes.html#ctypes.WinDLL) или [`OleDLL`](https://python-all.ru/3.0/library/ctypes.html#ctypes.OleDLL).12391240[`__getattr__()`](https://python-all.ru/3.0/reference/datamodel.html#object.__getattr__) обладает особым поведением: позволяет загрузить разделяемую библиотеку, обращаясь к ней как к атрибуту экземпляра загрузчика библиотек. Результат кэшируется, поэтому повторные обращения к атрибуту каждый раз возвращают ту же библиотеку.12411242#### `[ctypes.LibraryLoader.LoadLibrary]LoadLibrary(name)`12431244Загружает разделяемую библиотеку в процесс и возвращает её. Этот метод всегда возвращает новый экземпляр библиотеки.12451246Доступны следующие готовые загрузчики библиотек:12471248#### `ctypes.cdll`12491250Создаёт экземпляры12511252[`CDLL`](https://python-all.ru/3.0/library/ctypes.html#ctypes.CDLL)12531254.12551256#### `ctypes.windll`12571258Только для Windows: создаёт экземпляры12591260[`WinDLL`](https://python-all.ru/3.0/library/ctypes.html#ctypes.WinDLL)12611262.12631264#### `ctypes.oledll`12651266Только для Windows: создаёт экземпляры12671268[`OleDLL`](https://python-all.ru/3.0/library/ctypes.html#ctypes.OleDLL)12691270.12711272#### `ctypes.pydll`12731274Создаёт экземпляры12751276[`PyDLL`](https://python-all.ru/3.0/library/ctypes.html#ctypes.PyDLL)12771278.12791280Для прямого доступа к C Python API доступен готовый к использованию объект общей библиотеки Python:12811282#### `ctypes.pythonapi`12831284Экземпляр12851286[`PyDLL`](https://python-all.ru/3.0/library/ctypes.html#ctypes.PyDLL)12871288, который предоставляет функции C API Python в виде атрибутов. Обратите внимание: все эти функции считаются возвращающими C12891290`int`12911292, что, конечно, не всегда верно, поэтому необходимо присвоить правильный атрибут12931294`restype`12951296для работы с ними.12971298### Внешние функции12991300Как объяснялось в предыдущем разделе, внешние функции можно получить как атрибуты загруженных разделяемых библиотек. Созданные таким образом объекты функций по умолчанию принимают любое количество аргументов, принимают любые экземпляры данных ctypes в качестве аргументов и возвращают тип результата по умолчанию, указанный загрузчиком библиотеки. Они являются экземплярами закрытого класса:13011302#### `[ctypes._FuncPtr]class ctypes._FuncPtr`13031304Базовый класс для внешних функций, вызываемых из C.13051306Экземпляры внешних функций также являются C-совместимыми типами данных; они представляют указатели на функции C.13071308Это поведение можно настроить, присвоив значения специальным атрибутам объекта внешней функции.13091310#### `[ctypes._FuncPtr.restype]restype`13111312Присвойте тип ctypes для указания типа результата внешней функции. Используйте `None` для `void` – функции, не возвращающей значения.13131314Можно присвоить вызываемый объект Python, который не является типом ctypes; в этом случае считается, что функция возвращает C `int`, и вызываемый объект будет вызван с этим целым числом, что позволяет выполнить дополнительную обработку или проверку ошибок. Использование этого способа устарело; для более гибкой последующей обработки или проверки ошибок используйте тип данных ctypes в качестве [`restype`](https://python-all.ru/3.0/library/ctypes.html#ctypes._FuncPtr.restype) и присвойте вызываемый объект атрибуту [`errcheck`](https://python-all.ru/3.0/library/ctypes.html#ctypes._FuncPtr.errcheck).13151316#### `[ctypes._FuncPtr.argtypes]argtypes`13171318Назначьте кортеж типов ctypes, чтобы указать типы аргументов, которые принимает функция. Функции, использующие соглашение о вызове `stdcall`, могут быть вызваны только с тем же количеством аргументов, что и длина этого кортежа; функции, использующие соглашение о вызове C, также принимают дополнительные неуказанные аргументы.13191320Когда вызывается внешняя функция, каждый фактический аргумент передается методу класса `from_param()` элементов кортежа [`argtypes`](https://python-all.ru/3.0/library/ctypes.html#ctypes._FuncPtr.argtypes); этот метод позволяет адаптировать фактический аргумент к объекту, который принимает внешняя функция. Например, элемент [`c_char_p`](https://python-all.ru/3.0/library/ctypes.html#ctypes.c_char_p) в кортеже [`argtypes`](https://python-all.ru/3.0/library/ctypes.html#ctypes._FuncPtr.argtypes) преобразует строку Unicode, переданную в качестве аргумента, в байтовую строку по правилам преобразования ctypes.13211322Новое: теперь можно помещать в argtypes элементы, которые не являются типами ctypes, но каждый элемент должен иметь метод `from_param()`, возвращающий значение, пригодное для использования в качестве аргумента (целое число, строка, экземпляр ctypes). Это позволяет определять адаптеры, которые могут адаптировать пользовательские объекты как параметры функции.13231324#### `[ctypes._FuncPtr.errcheck]errcheck`13251326Этому атрибуту присваивается функция Python или другой вызываемый объект. Вызываемый объект будет вызван с тремя и более аргументами:13271328#### `callable(result, func, arguments)`13291330`result` – это то, что возвращает внешняя функция, как указано атрибутом [`restype`](https://python-all.ru/3.0/library/ctypes.html#ctypes._FuncPtr.restype).13311332`func` – это сам объект внешней функции, что позволяет повторно использовать один и тот же вызываемый объект для проверки или последующей обработки результатов нескольких функций.13331334`arguments` – это кортеж, содержащий параметры, изначально переданные при вызове функции, что позволяет специализировать поведение в зависимости от используемых аргументов.13351336Объект, возвращаемый этой функцией, будет возвращён из вызова внешней функции, но он также может проверить значение результата и возбудить исключение, если вызов внешней функции завершился неудачей.13371338#### `[ctypes.ArgumentError]exception ctypes.ArgumentError`13391340Это исключение возникает, когда вызов внешней функции не может преобразовать один из переданных аргументов.13411342### Прототипы функций13431344Внешние функции также можно создать, инстанцируя прототипы функций. Прототипы функций аналогичны прототипам функций в C; они описывают функцию (тип возвращаемого значения, типы аргументов, соглашение о вызове) без определения реализации. Фабричные функции необходимо вызывать с желаемым типом результата и типами аргументов функции.13451346#### `[ctypes.CFUNCTYPE]ctypes.CFUNCTYPE(restype, *argtypes, use_errno=False, use_last_error=False)`13471348Возвращаемый прототип функции создает функции, использующие стандартное соглашение о вызове C. Функция будет освобождать GIL во время вызова. Если13491350*use\_errno*13511352установлен в True, частная копия системной переменной13531354`errno`13551356в ctypes обменивается с реальным значением13571358`errno`13591360до и после вызова;13611362*use\_last\_error*13631364делает то же самое для кода ошибки Windows.13651366#### `[ctypes.WINFUNCTYPE]ctypes.WINFUNCTYPE(restype, *argtypes, use_errno=False, use_last_error=False)`13671368Только для Windows: возвращаемый прототип функции создаёт функции, использующие соглашение о вызове13691370`stdcall`13711372, за исключением Windows CE, где13731374[`WINFUNCTYPE()`](https://python-all.ru/3.0/library/ctypes.html#ctypes.WINFUNCTYPE)13751376совпадает с13771378[`CFUNCTYPE()`](https://python-all.ru/3.0/library/ctypes.html#ctypes.CFUNCTYPE)13791380. Функция освобождает GIL во время вызова.13811382*use\_errno*13831384и13851386*use\_last\_error*13871388имеют тот же смысл, что и выше.13891390#### `[ctypes.PYFUNCTYPE]ctypes.PYFUNCTYPE(restype, *argtypes)`13911392Созданный прототип функции создаёт функции, использующие соглашение о вызове Python. Функция13931394*не*13951396освобождает GIL во время вызова.13971398Прототипы функций, созданные этими фабричными функциями, могут быть созданы различными способами, в зависимости от типа и количества параметров в вызове:13991400> #### `prototype(address)`1401>1402> Возвращает внешнюю функцию по указанному адресу, который должен быть целым числом.1403>1404> #### `prototype(callable)`1405>1406> Создает вызываемую функцию C (функцию обратного вызова) из Python1407>1408> `callable`1409>1410> .1411>1412> #### `prototype(func_spec[, paramflags])`1413>1414> Возвращает внешнюю функцию, экспортируемую общей библиотекой.1415>1416> `func_spec`1417>1418> должен быть кортежем из двух элементов1419>1420> `(name_or_ordinal, library)`1421>1422> . Первый элемент – это имя экспортируемой функции в виде строки или порядковый номер экспортируемой функции в виде небольшого целого числа. Второй элемент – это экземпляр общей библиотеки.1423>1424> #### `prototype(vtbl_index, name[, paramflags[, iid]])`1425>1426> Возвращает внешнюю функцию, которая будет вызывать метод COM. `vtbl_index` – это индекс в таблице виртуальных функций, небольшое неотрицательное целое число. *name* – это имя метода COM. *iid* – это необязательный указатель на идентификатор интерфейса, который используется в расширенном отчете об ошибках.1427>1428> Методы COM используют специальное соглашение о вызове: они требуют указатель на интерфейс COM в качестве первого аргумента, в дополнение к тем параметрам, которые указаны в кортеже `argtypes`.1429>1430> Необязательный параметр *paramflags* создаёт обёртки внешних функций с гораздо большей функциональностью, чем описано выше.1431>1432> *paramflags* должен быть кортежем той же длины, что и `argtypes`.1433>1434> Каждый элемент этого кортежа содержит дополнительную информацию о параметре; он должен быть кортежем, содержащим один, два или три элемента.1435>1436> Первый элемент – целое число, содержащее комбинацию флагов направления для параметра:1437>1438> > **1**1439> >1440> > Задаёт входной параметр функции.1441> >1442> > **2**1443> >1444> > Выходной параметр. Внешняя функция заполняет значение.1445> >1446> > **4**1447> >1448> > Входной параметр, по умолчанию равный нулю.1449>1450> Необязательный второй элемент – имя параметра в виде строки. Если он указан, внешнюю функцию можно вызывать с именованными параметрами.1451>1452> Необязательный третий элемент – значение по умолчанию для этого параметра.14531454Этот пример демонстрирует, как обернуть функцию Windows `MessageBoxA` так, чтобы она поддерживала параметры по умолчанию и именованные аргументы. Объявление C из заголовочного файла Windows выглядит так:14551456```python1457WINUSERAPI int WINAPI1458MessageBoxA(1459 HWND hWnd ,1460 LPCSTR lpText,1461 LPCSTR lpCaption,1462 UINT uType);1463```14641465Вот обёртка с помощью `ctypes`:14661467```python1468>>> from ctypes import c_int, WINFUNCTYPE, windll1469>>> from ctypes.wintypes import HWND, LPCSTR, UINT1470>>> prototype = WINFUNCTYPE(c_int, HWND, LPCSTR, LPCSTR, UINT)1471>>> paramflags = (1, "hwnd", 0), (1, "text", "Hi"), (1, "caption", None), (1, "flags", 0)1472>>> MessageBox = prototype(("MessageBoxA", windll.user32), paramflags)1473>>>1474```14751476Теперь внешнюю функцию MessageBox можно вызывать следующими способами:14771478```python1479>>> MessageBox()1480>>> MessageBox(text="Spam, spam, spam")1481>>> MessageBox(flags=2, text="foo bar")1482>>>1483```14841485Второй пример демонстрирует выходные параметры. Функция win32 `GetWindowRect` получает размеры указанного окна, копируя их в структуру `RECT`, которую должен предоставить вызывающий код. Вот объявление C:14861487```python1488WINUSERAPI BOOL WINAPI1489GetWindowRect(1490 HWND hWnd,1491 LPRECT lpRect);1492```14931494Вот обёртка с помощью `ctypes`:14951496```python1497>>> from ctypes import POINTER, WINFUNCTYPE, windll, WinError1498>>> from ctypes.wintypes import BOOL, HWND, RECT1499>>> prototype = WINFUNCTYPE(BOOL, HWND, POINTER(RECT))1500>>> paramflags = (1, "hwnd"), (2, "lprect")1501>>> GetWindowRect = prototype(("GetWindowRect", windll.user32), paramflags)1502>>>1503```15041505Функции с выходными параметрами автоматически возвращают значение выходного параметра, если он один, или кортеж значений выходных параметров, если их несколько; таким образом, при вызове функция GetWindowRect теперь возвращает экземпляр RECT.15061507Выходные параметры можно комбинировать с протоколом `errcheck` для дальнейшей обработки вывода и проверки ошибок. Функция win32 API `GetWindowRect` возвращает `BOOL` для сигнализации об успехе или неудаче, поэтому эта функция могла бы выполнять проверку ошибок и возбуждать исключение при сбое вызова API:15081509```python1510>>> def errcheck(result, func, args):1511... if not result:1512... raise WinError()1513... return args1514...1515>>> GetWindowRect.errcheck = errcheck1516>>>1517```15181519Если функция `errcheck` возвращает кортеж аргументов, который она получила, без изменений, `ctypes` продолжает обычную обработку выходных параметров. Если требуется вернуть кортеж координат окна вместо экземпляра `RECT`, можно извлечь поля в функции и вернуть их; обычная обработка выполняться не будет.15201521```python1522>>> def errcheck(result, func, args):1523... if not result:1524... raise WinError()1525... rc = args[1]1526... return rc.left, rc.top, rc.bottom, rc.right1527...1528>>> GetWindowRect.errcheck = errcheck1529>>>1530```15311532### Вспомогательные функции15331534#### `[ctypes.addressof]ctypes.addressof(obj)`15351536Возвращает адрес буфера памяти в виде целого числа.15371538`obj`15391540должен быть экземпляром типа ctypes.15411542#### `[ctypes.alignment]ctypes.alignment(obj_or_type)`15431544Возвращает требования к выравниванию для типа ctypes.15451546`obj_or_type`15471548должен быть типом ctypes или экземпляром.15491550#### `[ctypes.byref]ctypes.byref(obj[, offset])`15511552Возвращает легковесный указатель на `obj`, который должен быть экземпляром типа ctypes. `offset` по умолчанию равен нулю и должен быть целым числом, которое будет добавлено к внутреннему значению указателя.15531554`byref(obj, offset)` соответствует следующему коду на C:15551556```python1557(((char *)&obj) + offset)1558```15591560Возвращаемый объект можно использовать только как параметр вызова внешней функции. Он ведет себя аналогично `pointer(obj)`, но создается гораздо быстрее.15611562#### `[ctypes.cast]ctypes.cast(obj, type)`15631564Эта функция аналогична оператору приведения типов в C. Она возвращает новый экземпляр15651566`type`15671568, который указывает на тот же блок памяти, что и15691570`obj`15711572.15731574`type`15751576должен быть типом указателя, а15771578`obj`15791580– объектом, который можно интерпретировать как указатель.15811582#### `[ctypes.create_string_buffer]ctypes.create_string_buffer(init_or_size[, size])`15831584Эта функция создаёт изменяемый символьный буфер. Возвращаемый объект – это массив ctypes из [`c_char`](https://python-all.ru/3.0/library/ctypes.html#ctypes.c_char).15851586`init_or_size` должен быть целым числом, задающим размер массива, или строкой, которая будет использоваться для инициализации элементов массива.15871588Если в качестве первого аргумента указана строка, буфер делается на один элемент больше длины строки, чтобы последний элемент массива был завершающим символом NUL. Вторым аргументом можно передать целое число, которое позволяет задать размер массива, если длина строки не должна использоваться.15891590Если первый параметр – строка в кодировке Unicode, она преобразуется в 8-битную строку по правилам преобразования ctypes.15911592#### `[ctypes.create_unicode_buffer]ctypes.create_unicode_buffer(init_or_size[, size])`15931594Эта функция создаёт изменяемый буфер символов Unicode. Возвращаемый объект – это массив ctypes из [`c_wchar`](https://python-all.ru/3.0/library/ctypes.html#ctypes.c_wchar).15951596`init_or_size` должен быть целым числом, задающим размер массива, или строкой в кодировке Unicode, которая будет использоваться для инициализации элементов массива.15971598Если в качестве первого аргумента указана строка в кодировке Unicode, буфер делается на один элемент больше длины строки, чтобы последний элемент массива был завершающим символом NUL. Вторым аргументом можно передать целое число, которое позволяет задать размер массива, если длина строки не должна использоваться.15991600Если первый параметр – 8-битная строка, она преобразуется в строку в кодировке Unicode по правилам преобразования ctypes.16011602#### `[ctypes.DllCanUnloadNow]ctypes.DllCanUnloadNow()`16031604Только Windows: эта функция является хуком, который позволяет реализовывать внутрипроцессные COM-серверы с помощью ctypes. Она вызывается из функции DllCanUnloadNow, которую экспортирует DLL расширения \_ctypes.16051606#### `[ctypes.DllGetClassObject]ctypes.DllGetClassObject()`16071608Только Windows: эта функция является хуком, который позволяет реализовывать внутрипроцессные COM-серверы с помощью ctypes. Она вызывается из функции DllGetClassObject, которую экспортирует DLL расширения16091610`_ctypes`16111612.16131614#### `[ctypes.util.find_library]ctypes.util.find_library(name)`16151616Пытается найти библиотеку и возвращает путь к ней. *name* – это имя библиотеки без префикса вроде `lib`, суффикса вроде `.so`, `.dylib` или номера версии (в такой форме имя используется для опции компоновщика в POSIX *-l*). Если библиотеку найти не удалось, возвращается `None`.16171618Точное поведение зависит от системы.16191620#### `[ctypes.util.find_msvcrt]ctypes.util.find_msvcrt()`16211622Только Windows: возвращает имя файла библиотеки времени выполнения VC, используемой Python и модулями расширения. Если имя библиотеки не удаётся определить, возвращается `None`.16231624Если необходимо освободить память, например, выделенную модулем расширения с помощью вызова `free(void *)`, важно использовать функцию из той же библиотеки, которая выделила память.16251626#### `[ctypes.FormatError]ctypes.FormatError([code])`16271628Только Windows: возвращает текстовое описание кода ошибки. Если код ошибки не указан, используется последний код ошибки, полученный вызовом функции Windows API GetLastError.16291630#### `[ctypes.GetLastError]ctypes.GetLastError()`16311632Только для Windows: Возвращает последний код ошибки, установленный Windows в вызывающем потоке. Эта функция вызывает непосредственно функцию Windows16331634*GetLastError()*16351636; она не возвращает внутреннюю для ctypes копию кода ошибки.16371638#### `[ctypes.get_errno]ctypes.get_errno()`16391640Возвращает текущее значение принадлежащей ctypes копии системной переменной16411642`errno`16431644в вызывающем потоке.16451646#### `[ctypes.get_last_error]ctypes.get_last_error()`16471648Только Windows: возвращает текущее значение переменной16491650`LastError`16511652(приватной копии ctypes системной переменной LastError) в вызывающем потоке.16531654#### `[ctypes.memmove]ctypes.memmove(dst, src, count)`16551656Аналогична стандартной библиотечной функции C memmove: копирует16571658*count*16591660байт из16611662`src`16631664в16651666*dst*16671668.16691670*dst*16711672и16731674`src`16751676должны быть целыми числами или экземплярами ctypes, которые могут быть преобразованы в указатели.16771678#### `[ctypes.memset]ctypes.memset(dst, c, count)`16791680Аналогична стандартной библиотечной функции C memset: заполняет блок памяти по адресу16811682*dst*16831684*count*16851686байтами значения16871688*c*16891690.16911692*dst*16931694должно быть целым числом, задающим адрес, или экземпляром ctypes.16951696#### `[ctypes.POINTER]ctypes.POINTER(type)`16971698Эта фабричная функция создаёт и возвращает новый тип указателя ctypes. Типы указателей кэшируются и повторно используются внутри, поэтому многократный вызов этой функции не требует больших затрат. type должен быть типом ctypes.16991700#### `[ctypes.pointer]ctypes.pointer(obj)`17011702Эта функция создаёт новый экземпляр указателя, указывающий на `obj`. Возвращаемый объект имеет тип POINTER(type(obj)).17031704Примечание: если нужно просто передать указатель на объект в вызов внешней функции, используйте `byref(obj)` – это намного быстрее.17051706#### `[ctypes.resize]ctypes.resize(obj, size)`17071708Эта функция изменяет размер внутреннего буфера памяти obj, который должен быть экземпляром типа ctypes. Невозможно сделать буфер меньше собственного размера типа объекта, задаваемого sizeof(type(obj)), но можно увеличить буфер.17091710#### `[ctypes.set_conversion_mode]ctypes.set_conversion_mode(encoding, errors)`17111712Эта функция задаёт правила, которые объекты ctypes используют при преобразовании между 8-битными строками и строками Unicode. Параметр encoding должен быть строкой, указывающей кодировку, например `'utf-8'` или `'mbcs'`, а errors – строка, задающая обработку ошибок кодирования/декодирования. Примеры возможных значений: `"strict"`, `"replace"` или `"ignore"`.17131714`set_conversion_mode` возвращает кортеж из двух элементов, содержащий предыдущие правила преобразования. В Windows начальные правила преобразования: `('mbcs', 'ignore')`, на других системах `('ascii', 'strict')`.17151716#### `[ctypes.set_errno]ctypes.set_errno(value)`17171718Устанавливает текущее значение принадлежащей ctypes копии системной переменной17191720`errno`17211722в вызывающем потоке равным17231724*value*17251726и возвращает предыдущее значение.17271728#### `[ctypes.set_last_error]ctypes.set_last_error(value)`17291730Только для Windows: устанавливает текущее значение приватной копии системной переменной17311732`LastError`17331734в вызывающем потоке в17351736*value*17371738и возвращает предыдущее значение.17391740#### `[ctypes.sizeof]ctypes.sizeof(obj_or_type)`17411742Возвращает размер в байтах буфера памяти ctypes-типа или экземпляра. Делает tо же самое, что и функция C17431744`sizeof()`17451746.17471748#### `[ctypes.string_at]ctypes.string_at(address[, size])`17491750Эта функция возвращает строку, начинающуюся по адресу памяти address. Если указан параметр size, он используется как размер; в противном случае строка считается завершающейся нулевым символом.17511752#### `[ctypes.WinError]ctypes.WinError(code=None, descr=None)`17531754Только Windows: эта функция, вероятно, – самое неудачно названное в ctypes. Она создаёт экземпляр WindowsError. Если17551756*code*17571758не указан, вызывается17591760`GetLastError`17611762для определения кода ошибки. Если17631764`descr`17651766не указан, вызывается17671768[`FormatError()`](https://python-all.ru/3.0/library/ctypes.html#ctypes.FormatError)17691770для получения текстового описания ошибки.17711772#### `[ctypes.wstring_at]ctypes.wstring_at(address)`17731774Эта функция возвращает широкую строку (wide character string), начинающуюся по адресу памяти17751776`address`17771778, в виде строки Unicode. Если17791780`size`17811782указан, он используется как количество символов строки; в противном случае строка считается завершающейся нулевым символом.17831784### Типы данных17851786#### `[ctypes._CData]class ctypes._CData`17871788Этот непубличный класс является общим базовым классом для всех типов данных ctypes. В частности, все экземпляры типов ctypes содержат блок памяти, хранящий совместимые с C данные; адрес этого блока памяти возвращается вспомогательной функцией `addressof()`. Другая переменная экземпляра доступна как [`_objects`](https://python-all.ru/3.0/library/ctypes.html#ctypes._CData._objects); она содержит другие объекты Python, которые должны оставаться в памяти на случай, если блок памяти содержит указатели.17891790Общие методы типов данных ctypes, все они являются методами класса (если точнее, это методы [*метакласса*](https://python-all.ru/3.0/glossary.html#term-metaclass)):17911792#### `[ctypes._CData.from_buffer]from_buffer(source[, offset])`17931794Этот метод возвращает экземпляр ctypes, который использует буфер объекта17951796`source`17971798. Объект17991800`source`18011802должен поддерживать интерфейс буфера с возможностью записи. Необязательный параметр18031804`offset`18051806задаёт смещение в буфере источника в байтах; по умолчанию оно равно нулю. Если исходный буфер недостаточно велик, вызывается исключение ValueError.18071808#### `[ctypes._CData.from_buffer_copy]from_buffer_copy(source[, offset])`18091810Этот метод создаёт экземпляр ctypes, копируя буфер из буфера исходного объекта, который должен быть доступен для чтения. Необязательный параметр18111812`offset`18131814задаёт смещение в буфере источника в байтах; по умолчанию оно равно нулю. Если исходный буфер недостаточно велик, вызывается исключение ValueError.18151816#### `[ctypes._CData.from_address]from_address(address)`18171818Этот метод возвращает экземпляр типа ctypes, использующий память, указанную параметром address, который должен быть целым числом.18191820#### `[ctypes._CData.from_param]from_param(obj)`18211822Этот метод приводит *obj* к типу ctypes. Он вызывается с фактическим объектом, используемым в вызове внешней функции, когда тип присутствует в кортеже `argtypes` этой функции; он должен вернуть объект, который можно использовать в качестве параметра вызова функции.18231824Все типы данных ctypes имеют реализацию этого метода класса по умолчанию, которая обычно возвращает `obj`, если он является экземпляром типа. Некоторые типы также принимают другие объекты.18251826#### `[ctypes._CData.in_dll]in_dll(library, name)`18271828Этот метод возвращает экземпляр типа ctypes, экспортируемый общей библиотекой.18291830*name*18311832– это имя символа, экспортирующего данные;18331834*library*18351836– загруженная общая библиотека.18371838Общие переменные экземпляра типов данных ctypes:18391840#### `[ctypes._CData._b_base_]_b_base_`18411842Иногда экземпляры данных ctypes не владеют блоком памяти, который содержат, а вместо этого разделяют часть блока памяти базового объекта. Член только для чтения18431844[`_b_base_`](https://python-all.ru/3.0/library/ctypes.html#ctypes._CData._b_base_)18451846является корневым объектом ctypes, которому принадлежит блок памяти.18471848#### `[ctypes._CData._b_needsfree_]_b_needsfree_`18491850Эта переменная только для чтения равна true, когда экземпляр данных ctypes сам выделил блок памяти, и false в противном случае.18511852#### `[ctypes._CData._objects]_objects`18531854Этот член может быть либо18551856`None`18571858, либо словарём, содержащим объекты Python, которые необходимо сохранять в памяти, чтобы содержимое блока памяти оставалось корректным. Этот объект предоставляется только для отладки; никогда не изменяйте содержимое этого словаря.18591860### Фундаментальные типы данных18611862#### `[ctypes._SimpleCData]class ctypes._SimpleCData`18631864Этот непубличный класс является базовым классом для всех фундаментальных типов данных ctypes. Он упоминается здесь, потому что содержит общие атрибуты фундаментальных типов данных ctypes. `_SimpleCData` является подклассом `_CData`, поэтому наследует их методы и атрибуты. Типы данных ctypes, которые не содержат указателей и не являются указателями, теперь могут быть сериализованы (pickled).18651866Экземпляры имеют один атрибут:18671868#### `[ctypes._SimpleCData.value]value`18691870Этот атрибут содержит фактическое значение экземпляра. Для целочисленных типов и типов указателей это целое число, для символьных типов – строка из одного символа, для типов указателей на символы – строка Python или строка Unicode.18711872Когда атрибут `value` извлекается из экземпляра ctypes, обычно каждый раз возвращается новый объект. `ctypes` *не* реализует возврат исходного объекта – всегда создается новый. То же самое верно для всех остальных экземпляров объектов ctypes.18731874Фундаментальные типы данных при возврате в качестве результатов вызовов внешних функций или, например, при извлечении полей структуры или элементов массива прозрачно преобразуются в собственные типы Python. Другими словами, если внешняя функция имеет `restype` равный [`c_char_p`](https://python-all.ru/3.0/library/ctypes.html#ctypes.c_char_p), вы всегда получите строку Python, *а не* экземпляр [`c_char_p`](https://python-all.ru/3.0/library/ctypes.html#ctypes.c_char_p).18751876Подклассы базовых типов данных *не* наследуют это поведение. Так, если `restype` внешней функции является подклассом [`c_void_p`](https://python-all.ru/3.0/library/ctypes.html#ctypes.c_void_p), то из вызова функции вы получите экземпляр этого подкласса. Разумеется, значение указателя можно получить, обратившись к атрибуту `value`.18771878Вот фундаментальные типы данных ctypes:18791880#### `[ctypes.c_byte]class ctypes.c_byte`18811882Представляет тип данных C signed char и интерпретирует значение как небольшое целое число. Конструктор принимает необязательный целочисленный инициализатор; проверка переполнения не выполняется.18831884#### `[ctypes.c_char]class ctypes.c_char`18851886Представляет тип данных C char и интерпретирует значение как один символ. Конструктор принимает необязательный строковый инициализатор, длина строки должна быть ровно один символ.18871888#### `[ctypes.c_char_p]class ctypes.c_char_p`18891890Представляет тип данных C char \*, который должен быть указателем на строку, завершающуюся нулевым символом. Конструктор принимает целочисленный адрес или строку.18911892#### `[ctypes.c_double]class ctypes.c_double`18931894Представляет тип данных C double. Конструктор принимает необязательный инициализатор типа float.18951896#### `[ctypes.c_longdouble]class ctypes.c_longdouble`18971898Представляет тип данных C long double. Конструктор принимает необязательный инициализатор типа float. На платформах, где18991900`sizeof(long double) == sizeof(double)`19011902, это псевдоним19031904[`c_double`](https://python-all.ru/3.0/library/ctypes.html#ctypes.c_double)19051906.19071908#### `[ctypes.c_float]class ctypes.c_float`19091910Представляет тип данных C float. Конструктор принимает необязательный инициализатор типа float.19111912#### `[ctypes.c_int]class ctypes.c_int`19131914Представляет тип данных C знаковый int. Конструктор принимает необязательный целочисленный инициализатор; проверка переполнения не выполняется. На платформах, где19151916`sizeof(int) == sizeof(long)`19171918, это псевдоним19191920[`c_long`](https://python-all.ru/3.0/library/ctypes.html#ctypes.c_long)19211922.19231924#### `[ctypes.c_int8]class ctypes.c_int8`19251926Представляет 8-битный тип данных C19271928`знаковый int`19291930. Обычно является псевдонимом19311932[`c_byte`](https://python-all.ru/3.0/library/ctypes.html#ctypes.c_byte)19331934.19351936#### `[ctypes.c_int16]class ctypes.c_int16`19371938Представляет 16-битный тип данных C знаковый int. Обычно является псевдонимом19391940[`c_short`](https://python-all.ru/3.0/library/ctypes.html#ctypes.c_short)19411942.19431944#### `[ctypes.c_int32]class ctypes.c_int32`19451946Представляет 32-битный тип данных C знаковый int. Обычно является псевдонимом19471948[`c_int`](https://python-all.ru/3.0/library/ctypes.html#ctypes.c_int)19491950.19511952#### `[ctypes.c_int64]class ctypes.c_int64`19531954Представляет 64-битный тип данных C19551956`знаковый int`19571958. Обычно является псевдонимом19591960[`c_longlong`](https://python-all.ru/3.0/library/ctypes.html#ctypes.c_longlong)19611962.19631964#### `[ctypes.c_long]class ctypes.c_long`19651966Представляет тип данных C19671968`знаковый long`19691970. Конструктор принимает необязательный целочисленный инициализатор; проверка переполнения не выполняется.19711972#### `[ctypes.c_longlong]class ctypes.c_longlong`19731974Представляет тип данных C19751976`знаковый long long`19771978. Конструктор принимает необязательный целочисленный инициализатор; проверка переполнения не выполняется.19791980#### `[ctypes.c_short]class ctypes.c_short`19811982Представляет тип данных C19831984`знаковый short`19851986. Конструктор принимает необязательный целочисленный инициализатор; проверка переполнения не выполняется.19871988#### `[ctypes.c_size_t]class ctypes.c_size_t`19891990Представляет тип данных C19911992`size_t`19931994.19951996#### `[ctypes.c_ubyte]class ctypes.c_ubyte`19971998Представляет тип данных C19992000`unsigned char`20012002; интерпретирует значение как небольшое целое число. Конструктор принимает необязательный целочисленный инициализатор; проверка переполнения не выполняется.20032004#### `[ctypes.c_uint]class ctypes.c_uint`20052006Представляет тип данных C20072008`unsigned int`20092010. Конструктор принимает необязательный целочисленный инициализатор; проверка переполнения не выполняется. На платформах, где20112012`sizeof(int) == sizeof(long)`20132014, это псевдоним20152016[`c_ulong`](https://python-all.ru/3.0/library/ctypes.html#ctypes.c_ulong)20172018.20192020#### `[ctypes.c_uint8]class ctypes.c_uint8`20212022Представляет беззнаковый целочисленный тип данных C размером 8 бит. Обычно является псевдонимом для20232024[`c_ubyte`](https://python-all.ru/3.0/library/ctypes.html#ctypes.c_ubyte)20252026.20272028#### `[ctypes.c_uint16]class ctypes.c_uint16`20292030Представляет беззнаковый целочисленный тип данных C размером 16 бит. Обычно является псевдонимом для20312032[`c_ushort`](https://python-all.ru/3.0/library/ctypes.html#ctypes.c_ushort)20332034.20352036#### `[ctypes.c_uint32]class ctypes.c_uint32`20372038Представляет беззнаковый целочисленный тип данных C размером 32 бит. Обычно является псевдонимом для20392040[`c_uint`](https://python-all.ru/3.0/library/ctypes.html#ctypes.c_uint)20412042.20432044#### `[ctypes.c_uint64]class ctypes.c_uint64`20452046Представляет беззнаковый целочисленный тип данных C размером 64 бит. Обычно является псевдонимом для20472048[`c_ulonglong`](https://python-all.ru/3.0/library/ctypes.html#ctypes.c_ulonglong)20492050.20512052#### `[ctypes.c_ulong]class ctypes.c_ulong`20532054Представляет тип данных C20552056`unsigned long`20572058. Конструктор принимает необязательный целочисленный инициализатор; проверка переполнения не выполняется.20592060#### `[ctypes.c_ulonglong]class ctypes.c_ulonglong`20612062Представляет тип данных C20632064`unsigned long long`20652066. Конструктор принимает необязательный целочисленный инициализатор; проверка переполнения не выполняется.20672068#### `[ctypes.c_ushort]class ctypes.c_ushort`20692070Представляет тип данных C20712072`unsigned short`20732074. Конструктор принимает необязательный целочисленный инициализатор; проверка переполнения не выполняется.20752076#### `[ctypes.c_void_p]class ctypes.c_void_p`20772078Представляет тип C20792080`void *`20812082. Значение представляется целым числом. Конструктор принимает необязательный целочисленный инициализатор.20832084#### `[ctypes.c_wchar]class ctypes.c_wchar`20852086Представляет тип данных C20872088`wchar_t`20892090и интерпретирует значение как строку из одного символа Unicode. Конструктор принимает необязательный строковый инициализатор; длина строки должна быть ровно один символ.20912092#### `[ctypes.c_wchar_p]class ctypes.c_wchar_p`20932094Представляет тип данных C20952096`wchar_t *`20972098, который должен быть указателем на широкую символьную строку, завершающуюся нулевым символом. Конструктор принимает целочисленный адрес или строку.20992100#### `[ctypes.c_bool]class ctypes.c_bool`21012102Представляет тип данных C21032104`bool`21052106(точнее, \_Bool из C99). Его значение может быть True или False, а конструктор принимает любой объект, который имеет логическое значение.21072108#### `[ctypes.HRESULT]class ctypes.HRESULT`21092110Только для Windows: представляет значение21112112[`HRESULT`](https://python-all.ru/3.0/library/ctypes.html#ctypes.HRESULT)21132114, которое содержит информацию об успехе или ошибке вызова функции или метода.21152116#### `[ctypes.py_object]class ctypes.py_object`21172118Представляет тип данных C21192120`PyObject *`21212122. Вызов без аргумента создаёт указатель21232124`NULL`21252126`PyObject *`21272128.21292130Модуль `ctypes.wintypes` предоставляет ряд других Windows-специфичных типов данных, например `HWND`, `WPARAM` или `DWORD`. Также определены некоторые полезные структуры, такие как `MSG` или `RECT`.21312132### Структурированные типы данных21332134#### `[ctypes.Union]class ctypes.Union(*args, **kw)`21352136Абстрактный базовый класс для объединений в собственном порядке байт.21372138#### `[ctypes.BigEndianStructure]class ctypes.BigEndianStructure(*args, **kw)`21392140Абстрактный базовый класс для структур в21412142*big endian*21432144порядке байтов.21452146#### `[ctypes.LittleEndianStructure]class ctypes.LittleEndianStructure(*args, **kw)`21472148Абстрактный базовый класс для структур в21492150*little endian*21512152порядке байтов.21532154Структуры с нестандартным порядком байтов не могут содержать поля типа указателя или любые другие типы данных, содержащие поля типа указателя.21552156#### `[ctypes.Structure]class ctypes.Structure(*args, **kw)`21572158Абстрактный базовый класс для структур в *нативном* порядке байтов.21592160Конкретные типы структур и объединений должны создаваться путем наследования от одного из этих типов и как минимум определять переменную класса [`_fields_`](https://python-all.ru/3.0/library/ctypes.html#ctypes.Structure._fields_). `ctypes` создаст [*дескрипторы*](https://python-all.ru/3.0/glossary.html#term-descriptor), которые позволяют читать и записывать поля через прямой доступ к атрибутам. Это21612162#### `[ctypes.Structure._fields_]_fields_`21632164Последовательность, определяющая поля структуры. Элементы должны быть 2-кортежами или 3-кортежами. Первый элемент – имя поля, второй элемент задает тип поля; это может быть любой тип данных ctypes.21652166Для полей целочисленных типов, таких как [`c_int`](https://python-all.ru/3.0/library/ctypes.html#ctypes.c_int), может быть указан третий необязательный элемент. Он должен быть небольшим положительным целым числом, определяющим разрядность поля.21672168Имена полей должны быть уникальными в пределах одной структуры или объединения. Это не проверяется, но при повторении имен доступно только одно поле.21692170Переменную класса [`_fields_`](https://python-all.ru/3.0/library/ctypes.html#ctypes.Structure._fields_) можно определить *после* оператора class, который определяет подкласс Structure; это позволяет создавать типы данных, которые прямо или косвенно ссылаются сами на себя:21712172```python2173class List(Structure):2174 pass2175List._fields_ = [("pnext", POINTER(List)),2176 ...2177 ]2178```21792180Однако переменная класса [`_fields_`](https://python-all.ru/3.0/library/ctypes.html#ctypes.Structure._fields_) должна быть определена до первого использования типа (создаётся экземпляр, вызывается `sizeof()` для него и так далее). Последующие присваивания переменной класса [`_fields_`](https://python-all.ru/3.0/library/ctypes.html#ctypes.Structure._fields_) вызовут исключение AttributeError.21812182Конструкторы подклассов Structure и Union принимают как позиционные, так и именованные аргументы. Позиционные аргументы используются для инициализации полей в том же порядке, в котором они указаны в определении [`_fields_`](https://python-all.ru/3.0/library/ctypes.html#ctypes.Structure._fields_), а именованные аргументы используются для инициализации полей с соответствующим именем.21832184Можно определять подподклассы типов структур; они наследуют поля базового класса плюс поля из [`_fields_`](https://python-all.ru/3.0/library/ctypes.html#ctypes.Structure._fields_), определённые в подподклассе, если таковые имеются.21852186#### `[ctypes.Structure._pack_]_pack_`21872188Необязательное небольшое целое число, позволяющее переопределить выравнивание полей структуры в экземпляре.21892190[`_pack_`](https://python-all.ru/3.0/library/ctypes.html#ctypes.Structure._pack_)21912192должен быть уже определён, когда присваивается21932194[`_fields_`](https://python-all.ru/3.0/library/ctypes.html#ctypes.Structure._fields_)21952196, иначе это не будет иметь эффекта.21972198#### `[ctypes.Structure._anonymous_]_anonymous_`21992200Необязательная последовательность, которая перечисляет имена безымянных (анонимных) полей. `_anonymous_` должен быть уже определён, когда присваивается [`_fields_`](https://python-all.ru/3.0/library/ctypes.html#ctypes.Structure._fields_), иначе он не будет иметь эффекта.22012202Поля, перечисленные в этой переменной, должны быть полями типа структуры или объединения. `ctypes` создаст дескрипторы в типе структуры, которые позволяют напрямую обращаться к вложенным полям без необходимости создавать поле структуры или объединения.22032204Вот пример типа (Windows):22052206```python2207class _U(Union):2208 _fields_ = [("lptdesc", POINTER(TYPEDESC)),2209 ("lpadesc", POINTER(ARRAYDESC)),2210 ("hreftype", HREFTYPE)]22112212class TYPEDESC(Structure):2213 _anonymous_ = ("u",)2214 _fields_ = [("u", _U),2215 ("vt", VARTYPE)]2216```22172218Структура `TYPEDESC` описывает тип данных COM; поле `vt` определяет, какое из полей объединения является действительным. Поскольку поле `u` определено как анонимное, теперь можно обращаться к членам напрямую через экземпляр TYPEDESC. `td.lptdesc` и `td.u.lptdesc` эквивалентны, но первый вариант быстрее, так как не требует создания временного экземпляра объединения:22192220```python2221td = TYPEDESC()2222td.vt = VT_PTR2223td.lptdesc = POINTER(some_type)2224td.u.lptdesc = POINTER(some_type)2225```22262227Можно определять подклассы структур, они наследуют поля базового класса. Если в определении подкласса есть отдельная переменная `_fields_`, указанные в ней поля добавляются к полям базового класса.22282229Конструкторы структур и объединений принимают как позиционные, так и именованные аргументы. Позиционные аргументы используются для инициализации полей-членов в том же порядке, в котором они указаны в `_fields_`. Именованные аргументы в конструкторе интерпретируются как присваивание атрибутов, поэтому они инициализируют `_fields_` с тем же именем или создают новые атрибуты для имён, отсутствующих в `_fields_`.22302231### Массивы и указатели22322233Ещё не написано – см. разделы [*Указатели*](https://python-all.ru/3.0/library/ctypes.html#ctypes-pointers) и раздел [*Массивы*](https://python-all.ru/3.0/library/ctypes.html#ctypes-arrays) в руководстве.2234