Документация Python неофициальный перевод

ctypes.md

2292 строк · 174.8 КБ · обычная страница · сырой текст · скачать

1> **Источник:** https://python-all.ru/3.16/library/ctypes.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# `ctypes` – библиотека для вызова внешних функций на Python89**Исходный код:** [Lib/ctypes](https://python-all.ru/3.16/library/ctypes.html)1011---1213`ctypes` – это библиотека для вызова внешних функций на Python. Она предоставляет совместимые с C типы данных и позволяет вызывать функции из DLL или разделяемых библиотек. Её можно использовать для обёртывания этих библиотек на чистом Python.1415Это [опциональный модуль](https://python-all.ru/3.16/glossary.html#term-optional-module). Если его нет в вашей копии CPython, обратитесь к документации от вашего дистрибьютора (то есть того, кто предоставил вам Python). Если вы дистрибьютор, обратитесь к [требованиям к опциональным модулям](https://python-all.ru/3.16/using/configure.html#optional-module-requirements).1617> **Предупреждение**18>19> `ctypes` предоставляет низкоуровневый доступ к нативным библиотекам и памяти процесса, обходя механизмы безопасности Python и позволяя выполнять произвольный нативный код. Некорректное использование может повредить данные и объекты, раскрыть конфиденциальную информацию, вызвать сбои или иным образом нарушить работу текущего процесса.2021## Руководство по ctypes2223Примечание: некоторые примеры кода ссылаются на тип [`c_int`](https://python-all.ru/3.16/library/ctypes.html#ctypes.c_int) модуля ctypes. На платформах, где `sizeof(long) == sizeof(int)` является псевдонимом для [`c_long`](https://python-all.ru/3.16/library/ctypes.html#ctypes.c_long). Поэтому не стоит удивляться, если при ожидании `c_int` выводится `c_long` – на самом деле это один и тот же тип.2425### Загрузка динамически подключаемых библиотек2627`ctypes` экспортирует объекты [`cdll`](https://python-all.ru/3.16/library/ctypes.html#ctypes.cdll), а в Windows – [`windll`](https://python-all.ru/3.16/library/ctypes.html#ctypes.windll) и [`oledll`](https://python-all.ru/3.16/library/ctypes.html#ctypes.oledll) для загрузки динамически подключаемых библиотек.2829Библиотеки загружаются обращением к ним как к атрибутам этих объектов. `cdll` загружает библиотеки, экспортирующие функции с использованием стандартного соглашения о вызовах `cdecl`, в то время как `windll` библиотеки вызывают функции по соглашению `stdcall`. [`oledll`](https://python-all.ru/3.16/library/ctypes.html#ctypes.oledll) также использует соглашение о вызовах `stdcall` и предполагает, что функции возвращают код ошибки Windows `HRESULT`. Этот код ошибки используется для автоматического возбуждения исключения [`OSError`](https://python-all.ru/3.16/library/exceptions.html#OSError) при сбое вызова функции.3031Изменено в версии 3.3: раньше ошибки Windows возбуждали [`WindowsError`](https://python-all.ru/3.16/library/exceptions.html#WindowsError), который теперь является псевдонимом [`OSError`](https://python-all.ru/3.16/library/exceptions.html#OSError).3233Вот несколько примеров для Windows. Обратите внимание, что `msvcrt` – это стандартная библиотека C от MS, содержащая большинство стандартных функций C, и использует соглашение о вызовах `cdecl`:3435```python36>>> from ctypes import *37>>> print(windll.kernel32)38<WinDLL 'kernel32', handle ... at ...>39>>> print(cdll.msvcrt)40<CDLL 'msvcrt', handle ... at ...>41>>> libc = cdll.msvcrt42>>>43```4445Windows автоматически добавляет обычный суффикс файла `.dll`.4647> **Примечание**48>49> Доступ к стандартной библиотеке C через `cdll.msvcrt` приведёт к использованию устаревшей версии библиотеки, которая может быть несовместима с той, которую использует Python. По возможности используйте встроенную функциональность Python или импортируйте и используйте модуль `msvcrt`.5051В других системах имя файла должно *включать* расширение для загрузки библиотеки, поэтому доступ через атрибуты не может быть использован для загрузки библиотек. Либо используйте метод [`LoadLibrary()`](https://python-all.ru/3.16/library/ctypes.html#ctypes.LibraryLoader.LoadLibrary) загрузчиков DLL, либо загрузите библиотеку, создав экземпляр [`CDLL`](https://python-all.ru/3.16/library/ctypes.html#ctypes.CDLL) с помощью вызова конструктора.5253Например, в Linux:5455```python56>>> cdll.LoadLibrary("libc.so.6")57<CDLL 'libc.so.6', handle ... at ...>58>>> libc = CDLL("libc.so.6")59>>> libc60<CDLL 'libc.so.6', handle ... at ...>61>>>62```6364В macOS:6566```python67>>> cdll.LoadLibrary("libc.dylib")68<CDLL 'libc.dylib', handle ... at ...>69>>> libc = CDLL("libc.dylib")70>>> libc71<CDLL 'libc.dylib', handle ... at ...>72```7374### Доступ к функциям из загруженных DLL7576Функции доступны как атрибуты объектов DLL:7778```python79>>> libc.printf80<_FuncPtr object at 0x...>81>>> print(windll.kernel32.GetModuleHandleA)82<_FuncPtr object at 0x...>83>>> print(windll.kernel32.MyOwnFunction)84Traceback (most recent call last):85  File "<stdin>", line 1, in <module>86  File "ctypes.py", line 239, in __getattr__87    func = _StdcallFuncPtr(name, self)88AttributeError: function 'MyOwnFunction' not found89>>>90```9192Обратите внимание, что системные DLL win32, такие как `kernel32` и `user32`, часто экспортируют как ANSI-, так и UNICODE-версии функций. Версия UNICODE экспортируется с добавлением `W` к имени, а версия ANSI – с добавлением `A` к имени. Функция win32 `GetModuleHandle`, которая возвращает *дескриптор модуля* для заданного имени модуля, имеет следующий C-прототип, и макрос используется для того, чтобы предоставить одну из них как `GetModuleHandle` в зависимости от того, определён ли UNICODE:9394```python95/* ANSI version */96HMODULE GetModuleHandleA(LPCSTR lpModuleName);97/* UNICODE version */98HMODULE GetModuleHandleW(LPCWSTR lpModuleName);99```100101*windll* не пытается выбрать одну из них магическим образом; необходимо получить доступ к нужной версии, явно указав `GetModuleHandleA` или `GetModuleHandleW`, и затем вызывать её с объектами bytes или string соответственно.102103Иногда DLL экспортируют функции с именами, которые не являются допустимыми идентификаторами Python, например `"??2@YAPAXI@Z"`. В этом случае нужно использовать [`getattr()`](https://python-all.ru/3.16/library/functions.html#getattr) для получения функции:104105```python106>>> getattr(cdll.msvcrt, "??2@YAPAXI@Z")107<_FuncPtr object at 0x...>108>>>109```110111В Windows некоторые DLL экспортируют функции не по имени, а по порядковому номеру. К таким функциям можно получить доступ, индексируя объект DLL по порядковому номеру:112113```python114>>> cdll.kernel32[1]115<_FuncPtr object at 0x...>116>>> cdll.kernel32[0]117Traceback (most recent call last):118  File "<stdin>", line 1, in <module>119  File "ctypes.py", line 310, in __getitem__120    func = _StdcallFuncPtr(name, self)121AttributeError: function ordinal 0 not found122>>>123```124125### Вызов функций126127Эти функции можно вызывать как любой другой вызываемый объект Python. В этом примере используется функция `rand()`, которая не принимает аргументов и возвращает псевдослучайное целое число:128129```python130>>> print(libc.rand())1311804289383132```133134В Windows можно вызвать функцию `GetModuleHandleA()`, которая возвращает дескриптор модуля win32 (передавая `None` в качестве единственного аргумента, чтобы вызвать её с указателем `NULL`):135136```python137>>> print(hex(windll.kernel32.GetModuleHandleA(None)))1380x1d000000139>>>140```141142[`ValueError`](https://python-all.ru/3.16/library/exceptions.html#ValueError) возбуждается, когда вызывается функция `stdcall` с соглашением о вызовах `cdecl` или наоборот:143144```python145>>> cdll.kernel32.GetModuleHandleA(None)146Traceback (most recent call last):147  File "<stdin>", line 1, in <module>148ValueError: Procedure probably called with not enough arguments (4 bytes missing)149>>>150151>>> windll.msvcrt.printf(b"spam")152Traceback (most recent call last):153  File "<stdin>", line 1, in <module>154ValueError: Procedure probably called with too many arguments (4 bytes in excess)155>>>156```157158Чтобы узнать правильное соглашение о вызовах, необходимо заглянуть в C-заголовочный файл или документацию вызываемой функции.159160В Windows `ctypes` использует структурированную обработку исключений win32 для предотвращения сбоев из-за ошибок общей защиты при вызове функций с недопустимыми значениями аргументов:161162```python163>>> windll.kernel32.GetModuleHandleA(32)164Traceback (most recent call last):165  File "<stdin>", line 1, in <module>166OSError: exception: access violation reading 0x00000020167>>>168```169170Модуль [`faulthandler`](https://python-all.ru/3.16/library/faulthandler.html#module-faulthandler) может помочь в отладке сбоев, таких как ошибки сегментации, вызванные ошибочными вызовами библиотеки C.171172`None`, целые числа, объекты bytes и (unicode) строки – единственные встроенные объекты Python, которые могут напрямую использоваться в качестве параметров в этих вызовах функций. `None` передаётся как указатель C `NULL`, объекты bytes и строки передаются как указатель на блок памяти, содержащий их данные (char\* или wchar\_t\*). Целые числа Python передаются как тип C int, используемый по умолчанию на платформе, их значение маскируется, чтобы соответствовать типу C.173174Прежде чем перейти к вызову функций с другими типами параметров, нужно узнать больше о типах данных `ctypes`.175176### Фундаментальные типы данных177178`ctypes` определяет несколько примитивных типов данных, совместимых с C:179180| Тип ctypes | Тип C | Тип Python | [`_type_`](https://python-all.ru/3.16/library/ctypes.html#ctypes._SimpleCData._type_) |181| --- | --- | --- | --- |182| [`c_bool`](https://python-all.ru/3.16/library/ctypes.html#ctypes.c_bool) | \_Bool | [`bool`](https://python-all.ru/3.16/library/functions.html#bool) | `'?'` |183| [`c_char`](https://python-all.ru/3.16/library/ctypes.html#ctypes.c_char) | char | Односимвольный [`bytes`](https://python-all.ru/3.16/library/stdtypes.html#bytes) | `'c'` |184| [`c_wchar`](https://python-all.ru/3.16/library/ctypes.html#ctypes.c_wchar) | `wchar_t` | Односимвольный [`str`](https://python-all.ru/3.16/library/stdtypes.html#str) | `'u'` |185| [`c_byte`](https://python-all.ru/3.16/library/ctypes.html#ctypes.c_byte) | char | [`int`](https://python-all.ru/3.16/library/functions.html#int) | `'b'` |186| [`c_ubyte`](https://python-all.ru/3.16/library/ctypes.html#ctypes.c_ubyte) | unsigned char | [`int`](https://python-all.ru/3.16/library/functions.html#int) | `'B'` |187| [`c_short`](https://python-all.ru/3.16/library/ctypes.html#ctypes.c_short) | short | [`int`](https://python-all.ru/3.16/library/functions.html#int) | `'h'` |188| [`c_ushort`](https://python-all.ru/3.16/library/ctypes.html#ctypes.c_ushort) | unsigned short | [`int`](https://python-all.ru/3.16/library/functions.html#int) | `'H'` |189| [`c_int`](https://python-all.ru/3.16/library/ctypes.html#ctypes.c_int) | int | [`int`](https://python-all.ru/3.16/library/functions.html#int) | `'i'` \* |190| [`c_int8`](https://python-all.ru/3.16/library/ctypes.html#ctypes.c_int8) | `int8_t` | [`int`](https://python-all.ru/3.16/library/functions.html#int) | \* |191| [`c_int16`](https://python-all.ru/3.16/library/ctypes.html#ctypes.c_int16) | `int16_t` | [`int`](https://python-all.ru/3.16/library/functions.html#int) | \* |192| [`c_int32`](https://python-all.ru/3.16/library/ctypes.html#ctypes.c_int32) | `int32_t` | [`int`](https://python-all.ru/3.16/library/functions.html#int) | \* |193| [`c_int64`](https://python-all.ru/3.16/library/ctypes.html#ctypes.c_int64) | `int64_t` | [`int`](https://python-all.ru/3.16/library/functions.html#int) | \* |194| [`c_uint`](https://python-all.ru/3.16/library/ctypes.html#ctypes.c_uint) | unsigned int | [`int`](https://python-all.ru/3.16/library/functions.html#int) | `'I'` \* |195| [`c_uint8`](https://python-all.ru/3.16/library/ctypes.html#ctypes.c_uint8) | `uint8_t` | [`int`](https://python-all.ru/3.16/library/functions.html#int) | \* |196| [`c_uint16`](https://python-all.ru/3.16/library/ctypes.html#ctypes.c_uint16) | `uint16_t` | [`int`](https://python-all.ru/3.16/library/functions.html#int) | \* |197| [`c_uint32`](https://python-all.ru/3.16/library/ctypes.html#ctypes.c_uint32) | `uint32_t` | [`int`](https://python-all.ru/3.16/library/functions.html#int) | \* |198| [`c_uint64`](https://python-all.ru/3.16/library/ctypes.html#ctypes.c_uint64) | `uint64_t` | [`int`](https://python-all.ru/3.16/library/functions.html#int) | \* |199| [`c_long`](https://python-all.ru/3.16/library/ctypes.html#ctypes.c_long) | long | [`int`](https://python-all.ru/3.16/library/functions.html#int) | `'l'` |200| [`c_ulong`](https://python-all.ru/3.16/library/ctypes.html#ctypes.c_ulong) | unsigned long | [`int`](https://python-all.ru/3.16/library/functions.html#int) | `'L'` |201| [`c_longlong`](https://python-all.ru/3.16/library/ctypes.html#ctypes.c_longlong) | long long | [`int`](https://python-all.ru/3.16/library/functions.html#int) | `'q'` \* |202| [`c_ulonglong`](https://python-all.ru/3.16/library/ctypes.html#ctypes.c_ulonglong) | unsigned long long | [`int`](https://python-all.ru/3.16/library/functions.html#int) | `'Q'` \* |203| [`c_size_t`](https://python-all.ru/3.16/library/ctypes.html#ctypes.c_size_t) | `size_t` | [`int`](https://python-all.ru/3.16/library/functions.html#int) | \* |204| [`c_ssize_t`](https://python-all.ru/3.16/library/ctypes.html#ctypes.c_ssize_t) | [`Py_ssize_t`](https://python-all.ru/3.16/c-api/intro.html#c.Py_ssize_t) | [`int`](https://python-all.ru/3.16/library/functions.html#int) | \* |205| [`c_time_t`](https://python-all.ru/3.16/library/ctypes.html#ctypes.c_time_t) | `time_t` | [`int`](https://python-all.ru/3.16/library/functions.html#int) | \* |206| [`c_float`](https://python-all.ru/3.16/library/ctypes.html#ctypes.c_float) | float | [`float`](https://python-all.ru/3.16/library/functions.html#float) | `'f'` |207| [`c_double`](https://python-all.ru/3.16/library/ctypes.html#ctypes.c_double) | double | [`float`](https://python-all.ru/3.16/library/functions.html#float) | `'d'` |208| [`c_longdouble`](https://python-all.ru/3.16/library/ctypes.html#ctypes.c_longdouble) | long double | [`float`](https://python-all.ru/3.16/library/functions.html#float) | `'g'` \* |209| [`c_char_p`](https://python-all.ru/3.16/library/ctypes.html#ctypes.c_char_p) | char\* (завершается NUL) | [`bytes`](https://python-all.ru/3.16/library/stdtypes.html#bytes) или `None` | `'z'` |210| [`c_wchar_p`](https://python-all.ru/3.16/library/ctypes.html#ctypes.c_wchar_p) | wchar\_t\* (завершается NUL) | [`str`](https://python-all.ru/3.16/library/stdtypes.html#str) или `None` | `'Z'` |211| [`c_void_p`](https://python-all.ru/3.16/library/ctypes.html#ctypes.c_void_p) | void\* | [`int`](https://python-all.ru/3.16/library/functions.html#int) или `None` | `'P'` |212| [`py_object`](https://python-all.ru/3.16/library/ctypes.html#ctypes.py_object) | [PyObject](https://python-all.ru/3.16/c-api/structures.html#c.PyObject)\* | [`object`](https://python-all.ru/3.16/library/functions.html#object) | `'O'` |213| [VARIANT\_BOOL](https://python-all.ru/3.16/library/ctypes.html#ctypes-wintypes) | short int | [`bool`](https://python-all.ru/3.16/library/functions.html#bool) | `'v'` |214215Кроме того, если в C и `libffi` поддерживается совместимая с IEC 60559 комплексная арифметика (приложение G), доступны следующие комплексные типы:216217| Тип ctypes | Тип C | Тип Python | [`_type_`](https://python-all.ru/3.16/library/ctypes.html#ctypes._SimpleCData._type_) |218| --- | --- | --- | --- |219| [`c_float_complex`](https://python-all.ru/3.16/library/ctypes.html#ctypes.c_float_complex) | float complex | [`complex`](https://python-all.ru/3.16/library/functions.html#complex) | `'Zf'` |220| [`c_double_complex`](https://python-all.ru/3.16/library/ctypes.html#ctypes.c_double_complex) | double complex | [`complex`](https://python-all.ru/3.16/library/functions.html#complex) | `'Zd'` |221| [`c_longdouble_complex`](https://python-all.ru/3.16/library/ctypes.html#ctypes.c_longdouble_complex) | long double complex | [`complex`](https://python-all.ru/3.16/library/functions.html#complex) | `'Zg'` |222223Изменено в версии 3.15: [`_type_`](https://python-all.ru/3.16/library/ctypes.html#ctypes._SimpleCData._type_) типы `F`, `D` и `G` были заменены на `Zf`, `Zd` и `Zg`.224225Все эти типы можно создать, вызвав их с необязательным инициализатором правильного типа и значения:226227```python228>>> c_int()229c_long(0)230>>> c_wchar_p("Hello, World")231c_wchar_p(140018365411392)232>>> c_ushort(-3)233c_ushort(65533)234>>>235```236237Конструкторы числовых типов преобразуют входные данные с помощью [`__bool__()`](https://python-all.ru/3.16/reference/datamodel.html#object.__bool__), [`__index__()`](https://python-all.ru/3.16/reference/datamodel.html#object.__index__) (для `int`), [`__float__()`](https://python-all.ru/3.16/reference/datamodel.html#object.__float__) или [`__complex__()`](https://python-all.ru/3.16/reference/datamodel.html#object.__complex__). Это означает, что [`c_bool`](https://python-all.ru/3.16/library/ctypes.html#ctypes.c_bool) принимает любой объект с логическим значением:238239```python240>>> empty_list = []241>>> c_bool(empty_list)242c_bool(False)243```244245Поскольку эти типы изменяемы, их значение можно изменить и впоследствии:246247```python248>>> i = c_int(42)249>>> print(i)250c_long(42)251>>> print(i.value)25242253>>> i.value = -99254>>> print(i.value)255-99256>>>257```258259Присваивание нового значения экземплярам типов-указателей [`c_char_p`](https://python-all.ru/3.16/library/ctypes.html#ctypes.c_char_p), [`c_wchar_p`](https://python-all.ru/3.16/library/ctypes.html#ctypes.c_wchar_p) и [`c_void_p`](https://python-all.ru/3.16/library/ctypes.html#ctypes.c_void_p) изменяет *адрес в памяти*, на который они указывают, *а не содержимое* блока памяти (разумеется, потому что строки Python неизменяемы):260261```python262>>> s = "Hello, World"263>>> c_s = c_wchar_p(s)264>>> print(c_s)265c_wchar_p(139966785747344)266>>> print(c_s.value)267Hello World268>>> c_s.value = "Hi, there"269>>> print(c_s)              # расположение в памяти изменилось270c_wchar_p(139966783348904)271>>> print(c_s.value)272Hi, there273>>> print(s)                # первый объект не изменился274Hello, World275>>>276```277278Однако следует соблюдать осторожность: не передавайте их функциям, ожидающим указатели на изменяемую память. Если нужны изменяемые блоки памяти, в ctypes есть функция [`create_string_buffer()`](https://python-all.ru/3.16/library/ctypes.html#ctypes.create_string_buffer), которая создаёт их разными способами. Текущее содержимое блока памяти можно получить (или изменить) через свойство `raw`; если нужно обратиться к нему как к строке, завершающейся NUL, используйте свойство `value`:279280```python281>>> from ctypes import *282>>> p = create_string_buffer(3)            # создать буфер размером 3 байта, инициализированный нулевыми байтами283>>> print(sizeof(p), repr(p.raw))2843 b'\x00\x00\x00'285>>> p = create_string_buffer(b"Hello")     # создать буфер, содержащий строку, завершающуюся нулевым байтом286>>> print(sizeof(p), repr(p.raw))2876 b'Hello\x00'288>>> print(repr(p.value))289b'Hello'290>>> p = create_string_buffer(b"Hello", 10) # создать буфер на 10 байт291>>> print(sizeof(p), repr(p.raw))29210 b'Hello\x00\x00\x00\x00\x00'293>>> p.value = b"Hi"294>>> print(sizeof(p), repr(p.raw))29510 b'Hi\x00lo\x00\x00\x00\x00\x00'296>>>297```298299Функция [`create_string_buffer()`](https://python-all.ru/3.16/library/ctypes.html#ctypes.create_string_buffer) заменяет старую функцию `c_buffer()` (которая всё ещё доступна как псевдоним). Чтобы создать изменяемый блок памяти, содержащий символы Юникода типа C `wchar_t`, используйте функцию [`create_unicode_buffer()`](https://python-all.ru/3.16/library/ctypes.html#ctypes.create_unicode_buffer).300301### Вызов функций, продолжение302303Обратите внимание: printf выводит в реальный стандартный поток вывода, *а не* в [`sys.stdout`](https://python-all.ru/3.16/library/sys.html#sys.stdout), поэтому эти примеры будут работать только в консоли, а не из *IDLE* или *PythonWin*:304305```python306>>> printf = libc.printf307>>> printf(b"Hello, %s\n", b"World!")308Hello, World!30914310>>> printf(b"Hello, %S\n", "World!")311Hello, World!31214313>>> printf(b"%d bottles of beer\n", 42)31442 bottles of beer31519316>>> printf(b"%f bottles of beer\n", 42.5)317Traceback (most recent call last):318  File "<stdin>", line 1, in <module>319ctypes.ArgumentError: argument 2: TypeError: Don't know how to convert parameter 2320>>>321```322323Как уже упоминалось, все типы Python, кроме целых чисел, строк и объектов bytes, должны быть обёрнуты в соответствующий тип `ctypes`, чтобы их можно было преобразовать в требуемый тип данных C:324325```python326>>> printf(b"An int %d, a double %f\n", 1234, c_double(3.14))327An int 1234, a double 3.14000032831329>>>330```331332### Вызов функций с переменным числом аргументов333334На многих платформах вызов функций с переменным числом аргументов через ctypes ничем не отличается от вызова функций с фиксированным числом параметров. Однако на некоторых платформах (в частности, ARM64 для Apple) соглашение о вызове для функций с переменным числом аргументов отличается от обычного.335336На этих платформах необходимо указать атрибут [`argtypes`](https://python-all.ru/3.16/library/ctypes.html#ctypes._CFuncPtr.argtypes) для обычных (невариативных) аргументов функции:337338```python339libc.printf.argtypes = [ctypes.c_char_p]340```341342Поскольку указание этого атрибута не ухудшает переносимость, рекомендуется всегда указывать [`argtypes`](https://python-all.ru/3.16/library/ctypes.html#ctypes._CFuncPtr.argtypes) для всех вариативных функций.343344### Вызов функций с собственными пользовательскими типами данных345346Можно также настроить преобразование аргументов `ctypes`, чтобы экземпляры собственных классов можно было использовать в качестве аргументов функций. `ctypes` ищет атрибут `_as_parameter_` и использует его как аргумент функции. Этот атрибут должен быть целым числом, строкой, байтами, экземпляром `ctypes` или объектом с атрибутом `_as_parameter_`:347348```python349>>> class Bottles:350...     def __init__(self, number):351...         self._as_parameter_ = number352...353>>> bottles = Bottles(42)354>>> printf(b"%d bottles of beer\n", bottles)35542 bottles of beer35619357>>>358```359360Если не нужно хранить данные экземпляра в переменной экземпляра `_as_parameter_`, можно определить [`@property`](https://python-all.ru/3.16/library/functions.html#property), который делает атрибут доступным по запросу.361362### Указание требуемых типов аргументов (прототипы функций)363364Можно указать требуемые типы аргументов функций, экспортируемых из DLL, задав атрибут [`argtypes`](https://python-all.ru/3.16/library/ctypes.html#ctypes._CFuncPtr.argtypes).365366[`argtypes`](https://python-all.ru/3.16/library/ctypes.html#ctypes._CFuncPtr.argtypes) должен быть последовательностью типов данных C (функция `printf()` вероятно, не лучший пример, поскольку она принимает переменное количество и разные типы параметров в зависимости от строки формата; с другой стороны, это довольно удобно для экспериментов с этой возможностью):367368```python369>>> printf.argtypes = [c_char_p, c_char_p, c_int, c_double]370>>> printf(b"String '%s', Int %d, Double %f\n", b"Hi", 10, 2.2)371String 'Hi', Int 10, Double 2.20000037237373>>>374```375376Указание формата защищает от несовместимых типов аргументов (как прототип для функции C) и пытается преобразовать аргументы в допустимые типы:377378```python379>>> printf(b"%d %d %d", 1, 2, 3)380Traceback (most recent call last):381  File "<stdin>", line 1, in <module>382ctypes.ArgumentError: argument 2: TypeError: 'int' object cannot be interpreted as ctypes.c_char_p383>>> printf(b"%s %d %f\n", b"X", 2, 3)384X 2 3.00000038513386>>>387```388389Если вы определили собственные классы, которые передаёте в вызовы функций, нужно реализовать метод класса [`from_param()`](https://python-all.ru/3.16/library/ctypes.html#ctypes._CData.from_param), чтобы их можно было использовать в последовательности [`argtypes`](https://python-all.ru/3.16/library/ctypes.html#ctypes._CFuncPtr.argtypes). Метод класса `from_param()` получает объект Python, переданный в вызов функции; он должен выполнить проверку типа или всё необходимое, чтобы убедиться, что объект приемлем, а затем вернуть сам объект, его атрибут `_as_parameter_` или то, что нужно передать в качестве аргумента функции C в данном случае. Результат должен быть целым числом, строкой, байтами, экземпляром `ctypes` или объектом с атрибутом `_as_parameter_`.390391### Типы возвращаемых значений392393По умолчанию предполагается, что функции возвращают тип C int. Другие типы возврата можно указать, задав атрибут [`restype`](https://python-all.ru/3.16/library/ctypes.html#ctypes._CFuncPtr.restype) объекта функции.394395Прототип C для `time()` – это `time_t time(time_t *)`. Поскольку `time_t` может иметь другой тип, нежели тип возврата по умолчанию int, следует указать атрибут `restype`:396397```python398>>> libc.time.restype = c_time_t399```400401Типы аргументов можно указать с помощью [`argtypes`](https://python-all.ru/3.16/library/ctypes.html#ctypes._CFuncPtr.argtypes):402403```python404>>> libc.time.argtypes = (POINTER(c_time_t),)405```406407Чтобы вызвать функцию с указателем `NULL` в качестве первого аргумента, используйте `None`:408409```python410>>> print(libc.time(None))4111150640792412```413414Вот более сложный пример: используется функция `strchr()`, которая ожидает указатель на строку и char, а возвращает указатель на строку:415416```python417>>> strchr = libc.strchr418>>> strchr(b"abcdef", ord("d"))4198059983420>>> strchr.restype = c_char_p    # c_char_p – указатель на строку421>>> strchr(b"abcdef", ord("d"))422b'def'423>>> print(strchr(b"abcdef", ord("x")))424None425>>>426```427428Чтобы избежать вызовов [`ord("x")`](https://python-all.ru/3.16/library/functions.html#ord) выше, можно задать атрибут [`argtypes`](https://python-all.ru/3.16/library/ctypes.html#ctypes._CFuncPtr.argtypes), и второй аргумент будет преобразован из одного символа объекта bytes Python в C char:429430```pycon431>>> strchr.restype = c_char_p432>>> strchr.argtypes = [c_char_p, c_char]433>>> strchr(b"abcdef", b"d")434b'def'435>>> strchr(b"abcdef", b"def")436Traceback (most recent call last):437ctypes.ArgumentError: argument 2: TypeError: one character bytes, bytearray or integer expected438>>> print(strchr(b"abcdef", b"x"))439None440>>> strchr(b"abcdef", b"d")441b'def'442>>>443```444445В качестве атрибута [`restype`](https://python-all.ru/3.16/library/ctypes.html#ctypes._CFuncPtr.restype) можно также использовать вызываемый объект Python (например, функцию или класс), если внешняя функция возвращает целое число. Этот вызываемый объект будет вызван с *целым числом*, которое вернула функция C, и результат этого вызова будет использован как результат вашего вызова функции. Это полезно для проверки кодов ошибок и автоматического возбуждения исключения:446447```python448>>> GetModuleHandle = windll.kernel32.GetModuleHandleA449>>> def ValidHandle(value):450...     if value == 0:451...         raise WinError()452...     return value453...454>>>455>>> GetModuleHandle.restype = ValidHandle456>>> GetModuleHandle(None)457486539264458>>> GetModuleHandle("something silly")459Traceback (most recent call last):460  File "<stdin>", line 1, in <module>461  File "<stdin>", line 3, in ValidHandle462OSError: [Errno 126] The specified module could not be found.463>>>464```465466`WinError` – это функция, которая вызывает Windows API `FormatMessage()` для получения строкового представления кода ошибки и *возвращает* исключение. `WinError` принимает необязательный параметр – код ошибки; если он не указан, функция вызывает [`GetLastError()`](https://python-all.ru/3.16/library/ctypes.html#ctypes.GetLastError) для его получения.467468Обратите внимание: гораздо более мощный механизм проверки ошибок доступен через атрибут [`errcheck`](https://python-all.ru/3.16/library/ctypes.html#ctypes._CFuncPtr.errcheck); подробнее см. в справочном руководстве.469470### Передача указателей (или: передача параметров по ссылке)471472Иногда функция C API ожидает в качестве параметра *указатель* на тип данных, обычно для записи в соответствующее место или если данные слишком велики для передачи по значению. Это также называется *передачей параметров по ссылке*.473474`ctypes` экспортирует функцию [`byref()`](https://python-all.ru/3.16/library/ctypes.html#ctypes.byref), которая используется для передачи параметров по ссылке. Того же эффекта можно достичь с помощью функции [`pointer()`](https://python-all.ru/3.16/library/ctypes.html#ctypes.pointer), хотя `pointer()` выполняет гораздо больше работы, так как создает реальный объект указателя, поэтому использовать `byref()` быстрее, если не нужен объект указателя в самом Python:475476```python477>>> i = c_int()478>>> f = c_float()479>>> s = create_string_buffer(b'\000' * 32)480>>> print(i.value, f.value, repr(s.value))4810 0.0 b''482>>> libc.sscanf(b"1 3.14 Hello", b"%d %f %s",483...             byref(i), byref(f), s)4843485>>> print(i.value, f.value, repr(s.value))4861 3.1400001049 b'Hello'487>>>488```489490### Структуры и объединения491492Структуры и объединения должны наследоваться от базовых классов [`Structure`](https://python-all.ru/3.16/library/ctypes.html#ctypes.Structure) и [`Union`](https://python-all.ru/3.16/library/ctypes.html#ctypes.Union), которые определены в модуле `ctypes`. Каждый подкласс должен определить атрибут [`_fields_`](https://python-all.ru/3.16/library/ctypes.html#ctypes.Structure._fields_). `_fields_` должен быть списком *2-кортежей*, содержащих *имя поля* и *тип поля*.493494Тип поля должен быть типом `ctypes`, таким как [`c_int`](https://python-all.ru/3.16/library/ctypes.html#ctypes.c_int), или любым другим производным типом `ctypes`: структура, объединение, массив, указатель.495496Вот простой пример структуры POINT, которая содержит два целых числа с именами *x* и *y*, а также показывает, как инициализировать структуру в конструкторе:497498```python499>>> from ctypes import *500>>> class POINT(Structure):501...     _fields_ = [("x", c_int),502...                 ("y", c_int)]503...504>>> point = POINT(10, 20)505>>> print(point.x, point.y)50610 20507>>> point = POINT(y=5)508>>> print(point.x, point.y)5090 5510>>> POINT(1, 2, 3)511Traceback (most recent call last):512  File "<stdin>", line 1, in <module>513TypeError: too many initializers514>>>515```516517Однако можно создавать гораздо более сложные структуры. Структура может сама содержать другие структуры, используя структуру в качестве типа поля.518519Вот структура RECT, которая содержит две точки с именами *upperleft* и *lowerright*:520521```python522>>> class RECT(Structure):523...     _fields_ = [("upperleft", POINT),524...                 ("lowerright", POINT)]525...526>>> rc = RECT(point)527>>> print(rc.upperleft.x, rc.upperleft.y)5280 5529>>> print(rc.lowerright.x, rc.lowerright.y)5300 0531>>>532```533534Вложенные структуры также можно инициализировать в конструкторе несколькими способами:535536```python537>>> r = RECT(POINT(1, 2), POINT(3, 4))538>>> r = RECT((1, 2), (3, 4))539```540541Поля [дескрипторы](https://python-all.ru/3.16/glossary.html#term-descriptor) можно получить из *класса*, они полезны для отладки, так как предоставляют полезную информацию. См. [`CField`](https://python-all.ru/3.16/library/ctypes.html#ctypes.CField):542543```python544>>> POINT.x545<ctypes.CField 'x' type=c_int, ofs=0, size=4>546>>> POINT.y547<ctypes.CField 'y' type=c_int, ofs=4, size=4>548>>>549```550551> **Предупреждение**552>553> `ctypes` не поддерживает передачу объединений или структур с битовыми полями в функции по значению. Хотя это может работать на 32-битной x86, библиотека не гарантирует работу в общем случае. Объединения и структуры с битовыми полями всегда следует передавать в функции по указателю.554555### Расположение структуры/объединения, выравнивание и порядок байт556557По умолчанию поля Structure и Union располагаются так же, как это делает компилятор C. Это поведение можно полностью переопределить, указав атрибут класса [`_layout_`](https://python-all.ru/3.16/library/ctypes.html#ctypes.Structure._layout_) в определении подкласса; подробнее см. в документации атрибута.558559Можно указать максимальное выравнивание для полей и/или самой структуры, установив соответствующие атрибуты класса [`_pack_`](https://python-all.ru/3.16/library/ctypes.html#ctypes.Structure._pack_) и/или [`_align_`](https://python-all.ru/3.16/library/ctypes.html#ctypes.Structure._align_). Подробнее см. в документации атрибута.560561`ctypes` использует собственный порядок байт для Structures и Unions. Для создания структур с нестандартным порядком байт можно использовать один из базовых классов [`BigEndianStructure`](https://python-all.ru/3.16/library/ctypes.html#ctypes.BigEndianStructure), [`LittleEndianStructure`](https://python-all.ru/3.16/library/ctypes.html#ctypes.LittleEndianStructure), [`BigEndianUnion`](https://python-all.ru/3.16/library/ctypes.html#ctypes.BigEndianUnion) и [`LittleEndianUnion`](https://python-all.ru/3.16/library/ctypes.html#ctypes.LittleEndianUnion). Эти классы не могут содержать поля-указатели.562563### Битовые поля в структурах и объединениях564565Можно создавать структуры и объединения, содержащие битовые поля. Битовые поля возможны только для целочисленных полей, ширина бита задается третьим элементом в кортежах [`_fields_`](https://python-all.ru/3.16/library/ctypes.html#ctypes.Structure._fields_):566567```python568>>> class Int(Structure):569...     _fields_ = [("first_16", c_int, 16),570...                 ("second_16", c_int, 16)]571...572>>> print(Int.first_16)573<ctypes.CField 'first_16' type=c_int, ofs=0, bit_size=16, bit_offset=0>574>>> print(Int.second_16)575<ctypes.CField 'second_16' type=c_int, ofs=0, bit_size=16, bit_offset=16>576```577578Важно отметить, что распределение и расположение битовых полей в памяти не определены стандартом C; их реализация зависит от компилятора. По умолчанию Python пытается соответствовать поведению «родного» компилятора для текущей платформы. Подробнее о поведении по умолчанию и о том, как его изменить, см. в атрибуте [`_layout_`](https://python-all.ru/3.16/library/ctypes.html#ctypes.Structure._layout_).579580### Массивы581582Массивы – это последовательности, содержащие фиксированное количество экземпляров одного типа.583584Рекомендуемый способ создания типов массивов – умножение типа данных на положительное целое число:585586```python587TenPointsArrayType = POINT * 10588```589590Вот пример несколько искусственного типа данных – структуры, содержащей 4 точки среди прочего:591592```python593>>> from ctypes import *594>>> class POINT(Structure):595...     _fields_ = ("x", c_int), ("y", c_int)596...597>>> class MyStruct(Structure):598...     _fields_ = [("a", c_int),599...                 ("b", c_float),600...                 ("point_array", POINT * 4)]601>>>602>>> print(len(MyStruct().point_array))6034604>>>605```606607Экземпляры создаются обычным способом – вызовом класса:608609```python610arr = TenPointsArrayType()611for pt in arr:612    print(pt.x, pt.y)613```614615Приведенный выше код выводит серию строк `0 0`, потому что содержимое массива инициализируется нулями.616617Можно также указать инициализаторы правильного типа:618619```python620>>> from ctypes import *621>>> TenIntegers = c_int * 10622>>> ii = TenIntegers(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)623>>> print(ii)624<c_long_Array_10 object at 0x...>625>>> for i in ii: print(i, end=" ")626...6271 2 3 4 5 6 7 8 9 10628>>>629```630631### Указатели632633Экземпляры указателей создаются вызовом функции [`pointer()`](https://python-all.ru/3.16/library/ctypes.html#ctypes.pointer) для типа `ctypes`:634635```python636>>> from ctypes import *637>>> i = c_int(42)638>>> pi = pointer(i)639>>>640```641642Экземпляры указателей имеют атрибут [`contents`](https://python-all.ru/3.16/library/ctypes.html#ctypes._Pointer.contents), который возвращает объект, на который указывает указатель, – объект `i` выше:643644```python645>>> pi.contents646c_long(42)647>>>648```649650Обратите внимание, что `ctypes` не поддерживает OOR (возврат исходного объекта); он создает новый, эквивалентный объект каждый раз при получении атрибута:651652```python653>>> pi.contents is i654False655>>> pi.contents is pi.contents656False657>>>658```659660Присваивание другого экземпляра [`c_int`](https://python-all.ru/3.16/library/ctypes.html#ctypes.c_int) атрибуту contents указателя заставит указатель указывать на область памяти, где этот экземпляр хранится:661662```python663>>> i = c_int(99)664>>> pi.contents = i665>>> pi.contents666c_long(99)667>>>668```669670Экземпляры указателей также можно индексировать целыми числами:671672```python673>>> pi[0]67499675>>>676```677678Присваивание целочисленному индексу изменяет значение, на которое указывает указатель:679680```python681>>> print(i)682c_long(99)683>>> pi[0] = 22684>>> print(i)685c_long(22)686>>>687```688689It 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.690691Под капотом функция [`pointer()`](https://python-all.ru/3.16/library/ctypes.html#ctypes.pointer) делает больше, чем просто создание экземпляров указателей: сначала ей нужно создать *типы* указателей. Это делается с помощью функции [`POINTER()`](https://python-all.ru/3.16/library/ctypes.html#ctypes.POINTER), которая принимает любой тип `ctypes` и возвращает новый тип:692693```python694>>> PI = POINTER(c_int)695>>> PI696<class 'ctypes.LP_c_long'>697>>> PI(42)698Traceback (most recent call last):699  File "<stdin>", line 1, in <module>700TypeError: expected c_long instead of int701>>> PI(c_int(42))702<ctypes.LP_c_long object at 0x...>703>>>704```705706Вызов типа указателя без аргументов создаёт нулевой указатель `NULL`. Нулевые указатели `NULL` имеют `False` ложное булево значение:707708```python709>>> null_ptr = POINTER(c_int)()710>>> print(bool(null_ptr))711False712>>>713```714715`ctypes` проверяет на `NULL` при разыменовании указателей (но разыменование недействительных не-`NULL` указателей приведёт к аварийному завершению Python):716717```python718>>> null_ptr[0]719Traceback (most recent call last):720    ....721ValueError: NULL pointer access722>>>723724>>> null_ptr[0] = 1234725Traceback (most recent call last):726    ....727ValueError: NULL pointer access728>>>729```730731### Потокобезопасность без GIL732733Начиная с Python 3.13, [GIL](https://python-all.ru/3.16/glossary.html#term-GIL) можно отключить в [сборке со свободными потоками](https://python-all.ru/3.16/glossary.html#term-free-threaded-build). В ctypes одновременное чтение и запись в один объект безопасны, но не для нескольких объектов:734735> ```pycon736> >>> number = c_int(42)737> >>> pointer_a = pointer(number)738> >>> pointer_b = pointer(number)739> ```740741В приведённом примере одному объекту безопасно одновременно читать и писать по адресу, только если GIL отключён. Таким образом, `pointer_a` может быть общим и доступным для записи из нескольких потоков, но только если `pointer_b` не пытается делать то же самое. Если это проблема, рассмотрите использование [`threading.Lock`](https://python-all.ru/3.16/library/threading.html#threading.Lock) для синхронизации доступа к памяти:742743> ```pycon744> >>> import threading745> >>> lock = threading.Lock()746> >>> # Поток 1747> >>> with lock:748> ...    pointer_a.contents = 24749> >>> # Поток 2750> >>> with lock:751> ...    pointer_b.contents = 42752> ```753754### Преобразования типов755756Обычно ctypes выполняет строгую проверку типов. Это означает, что если `POINTER(c_int)` указан в [`argtypes`](https://python-all.ru/3.16/library/ctypes.html#ctypes._CFuncPtr.argtypes) списке аргументов функции или в качестве типа поля структуры, принимаются только экземпляры точно того же типа. Из этого правила есть несколько исключений, когда ctypes принимает другие объекты. Например, можно передать совместимые экземпляры массивов вместо типов указателей. Так, для `POINTER(c_int)` ctypes принимает массив c\_int:757758```python759>>> class Bar(Structure):760...     _fields_ = [("count", c_int), ("values", POINTER(c_int))]761...762>>> bar = Bar()763>>> bar.values = (c_int * 3)(1, 2, 3)764>>> bar.count = 3765>>> for i in range(bar.count):766...     print(bar.values[i])767...768176927703771>>>772```773774Кроме того, если аргумент функции явно объявлен как тип указателя (например, `POINTER(c_int)`) в [`argtypes`](https://python-all.ru/3.16/library/ctypes.html#ctypes._CFuncPtr.argtypes), в функцию можно передать объект типа, на который указывает указатель (в данном случае `c_int`). В этом случае ctypes автоматически применит необходимое преобразование [`byref()`](https://python-all.ru/3.16/library/ctypes.html#ctypes.byref).775776Чтобы установить поле типа POINTER в `NULL`, можно присвоить `None`:777778```python779>>> bar.values = None780>>>781```782783Иногда встречаются экземпляры несовместимых типов. В C можно привести один тип к другому. `ctypes` предоставляет функцию [`cast()`](https://python-all.ru/3.16/library/ctypes.html#ctypes.cast), которую можно использовать аналогичным образом. Структура `Bar`, определённая выше, принимает указатели `POINTER(c_int)` или массивы [`c_int`](https://python-all.ru/3.16/library/ctypes.html#ctypes.c_int) для своего поля `values`, но не экземпляры других типов:784785```python786>>> bar.values = (c_byte * 4)()787Traceback (most recent call last):788  File "<stdin>", line 1, in <module>789TypeError: incompatible types, c_byte_Array_4 instance instead of LP_c_long instance790>>>791```792793Для таких случаев удобна функция [`cast()`](https://python-all.ru/3.16/library/ctypes.html#ctypes.cast).794795Функцию [`cast()`](https://python-all.ru/3.16/library/ctypes.html#ctypes.cast) можно использовать для приведения экземпляра ctypes к указателю на другой тип данных ctypes. `cast()` принимает два параметра: объект ctypes, который является или может быть преобразован в указатель какого-либо вида, и тип указателя ctypes. Она возвращает экземпляр второго аргумента, который ссылается на тот же блок памяти, что и первый аргумент:796797```python798>>> a = (c_byte * 4)()799>>> cast(a, POINTER(c_int))800<ctypes.LP_c_long object at ...>801>>>802```803804Таким образом, [`cast()`](https://python-all.ru/3.16/library/ctypes.html#ctypes.cast) можно использовать для присваивания полю `values` структуры `Bar`:805806```python807>>> bar = Bar()808>>> bar.values = cast((c_byte * 4)(), POINTER(c_int))809>>> print(bar.values[0])8100811>>>812```813814### Неполные типы815816*Неполные типы* – это структуры, объединения или массивы, члены которых ещё не определены. В C они задаются опережающими объявлениями, которые определяются позже:817818```python819struct cell; /* forward declaration */820821struct cell {822    char *name;823    struct cell *next;824};825```826827Прямой перевод в код ctypes выглядел бы так, но это не работает:828829```python830>>> class cell(Structure):831...     _fields_ = [("name", c_char_p),832...                 ("next", POINTER(cell))]833...834Traceback (most recent call last):835  File "<stdin>", line 1, in <module>836  File "<stdin>", line 2, in cell837NameError: name 'cell' is not defined838>>>839```840841потому что новый `class cell` недоступен внутри самого определения класса. В `ctypes` можно определить класс `cell` и задать атрибут [`_fields_`](https://python-all.ru/3.16/library/ctypes.html#ctypes.Structure._fields_) позже, после определения класса:842843```python844>>> from ctypes import *845>>> class cell(Structure):846...     pass847...848>>> cell._fields_ = [("name", c_char_p),849...                  ("next", POINTER(cell))]850>>>851```852853Попробуем. Создадим два экземпляра `cell`, заставим их указывать друг на друга и, наконец, пройдём по цепочке указателей несколько раз:854855```python856>>> c1 = cell()857>>> c1.name = b"foo"858>>> c2 = cell()859>>> c2.name = b"bar"860>>> c1.next = pointer(c2)861>>> c2.next = pointer(c1)862>>> p = c1863>>> for i in range(8):864...     print(p.name, end=" ")865...     p = p.next[0]866...867foo bar foo bar foo bar foo bar868>>>869```870871### Функции обратного вызова872873`ctypes` позволяет создавать указатели на вызываемые функции C из вызываемых объектов Python. Их иногда называют *функциями обратного вызова*.874875Сначала нужно создать класс для функции обратного вызова. Этот класс знает соглашение о вызове, тип возвращаемого значения, а также количество и типы аргументов, которые будет получать эта функция.876877Фабричная функция [`CFUNCTYPE()`](https://python-all.ru/3.16/library/ctypes.html#ctypes.CFUNCTYPE) создаёт типы для функций обратного вызова, используя соглашение о вызове `cdecl`. В Windows фабричная функция [`WINFUNCTYPE()`](https://python-all.ru/3.16/library/ctypes.html#ctypes.WINFUNCTYPE) создаёт типы для функций обратного вызова, используя соглашение о вызове `stdcall`.878879Обе эти фабричные функции вызываются с типом результата в качестве первого аргумента, а ожидаемые типы аргументов функции обратного вызова передаются как остальные аргументы.880881В качестве примера будет показано использование функции `qsort()` из стандартной библиотеки C, которая сортирует элементы с помощью функции обратного вызова. `qsort()` будет использована для сортировки массива целых чисел:882883```python884>>> IntArray5 = c_int * 5885>>> ia = IntArray5(5, 1, 7, 33, 99)886>>> qsort = libc.qsort887>>> qsort.restype = None888>>>889```890891`qsort()` должна вызываться с указателем на сортируемые данные, количеством элементов в массиве данных, размером одного элемента и указателем на функцию сравнения – функцию обратного вызова. Затем функция обратного вызова будет вызвана с двумя указателями на элементы; она должна вернуть отрицательное целое число, если первый элемент меньше второго, ноль – если они равны, и положительное – в противном случае.892893Итак, наша функция обратного вызова получает указатели на целые числа и должна вернуть целое число. Сначала создаётся `type` для функции обратного вызова:894895```python896>>> CMPFUNC = CFUNCTYPE(c_int, POINTER(c_int), POINTER(c_int))897>>>898```899900Для начала приведём простую функцию обратного вызова, которая выводит передаваемые ей значения:901902```python903>>> def py_cmp_func(a, b):904...     print("py_cmp_func", a[0], b[0])905...     return 0906...907>>> cmp_func = CMPFUNC(py_cmp_func)908>>>909```910911```python912>>> qsort(ia, len(ia), sizeof(c_int), cmp_func)913py_cmp_func 5 1914py_cmp_func 33 99915py_cmp_func 7 33916py_cmp_func 5 7917py_cmp_func 1 7918>>>919```920921Теперь можно по-настоящему сравнить два элемента и вернуть полезный результат:922923```python924>>> def py_cmp_func(a, b):925...     print("py_cmp_func", a[0], b[0])926...     return a[0] - b[0]927...928>>>929>>> qsort(ia, len(ia), sizeof(c_int), CMPFUNC(py_cmp_func))930py_cmp_func 5 1931py_cmp_func 33 99932py_cmp_func 7 33933py_cmp_func 1 7934py_cmp_func 5 7935>>>936```937938Как легко проверить, наш массив теперь отсортирован:939940```python941>>> for i in ia: print(i, end=" ")942...9431 5 7 33 99944>>>945```946947Фабрики функций могут использоваться как фабрики декораторов, так что можно просто написать:948949```python950>>> @CFUNCTYPE(c_int, POINTER(c_int), POINTER(c_int))951... def py_cmp_func(a, b):952...     print("py_cmp_func", a[0], b[0])953...     return a[0] - b[0]954...955>>> qsort(ia, len(ia), sizeof(c_int), py_cmp_func)956py_cmp_func 5 1957py_cmp_func 33 99958py_cmp_func 7 33959py_cmp_func 1 7960py_cmp_func 5 7961>>>962```963964> **Примечание**965>966> Необходимо сохранять ссылки на объекты [`CFUNCTYPE()`](https://python-all.ru/3.16/library/ctypes.html#ctypes.CFUNCTYPE), пока они используются из кода на C. `ctypes` этого не делает, и если не сохранять, они могут быть собраны сборщиком мусора, что приведет к краху программы при вызове колбэка.967>968> Также обратите внимание, что если функция обратного вызова вызывается в потоке, созданном вне контроля Python (например, внешним кодом, вызывающим колбэк), ctypes создает новый фиктивный поток Python при каждом вызове. Такое поведение корректно для большинства целей, но означает, что значения, сохраненные с помощью [`threading.local`](https://python-all.ru/3.16/library/threading.html#threading.local), *не* будут сохраняться между разными колбэками, даже если эти вызовы производятся из одного и того же потока C.969970### Доступ к значениям, экспортируемым из DLL971972Некоторые разделяемые библиотеки экспортируют не только функции, но и переменные. Примером в самой библиотеке Python является [`Py_Version`](https://python-all.ru/3.16/c-api/apiabiversion.html#c.Py_Version) – номер версии среды выполнения Python, закодированный в виде одного целочисленного константного значения.973974`ctypes` может получать доступ к таким значениям с помощью методов класса [`in_dll()`](https://python-all.ru/3.16/library/ctypes.html#ctypes._CData.in_dll) соответствующего типа. *pythonapi* – это предопределенный символ, предоставляющий доступ к C API Python:975976```python977>>> version = ctypes.c_int.in_dll(ctypes.pythonapi, "Py_Version")978>>> print(hex(version.value))9790x30c00a0980```981982Расширенный пример, также демонстрирующий использование указателей, обращается к указателю [`PyImport_FrozenModules`](https://python-all.ru/3.16/c-api/import.html#c.PyImport_FrozenModules), экспортируемому Python.983984Цитируя документацию для этого значения:985986> Этот указатель инициализируется так, чтобы указывать на массив записей [`_frozen`](https://python-all.ru/3.16/c-api/import.html#c._frozen), завершающийся записью, все члены которой равны `NULL` или нулю. Когда замороженный модуль импортируется, он ищется в этой таблице. Сторонний код может этим воспользоваться, чтобы предоставить динамически создаваемую коллекцию замороженных модулей.987988Таким образом, манипуляции с этим указателем могут оказаться полезными. Чтобы ограничить размер примера, мы показываем только то, как эту таблицу можно прочитать с помощью `ctypes`:989990```python991>>> from ctypes import *992>>>993>>> class struct_frozen(Structure):994...     _fields_ = [("name", c_char_p),995...                 ("code", POINTER(c_ubyte)),996...                 ("size", c_int),997...                 ("get_code", POINTER(c_ubyte)),  # Указатель на функцию998...                ]999...1000>>>1001```10021003Мы определили тип данных [`_frozen`](https://python-all.ru/3.16/c-api/import.html#c._frozen), поэтому можем получить указатель на таблицу:10041005```python1006>>> FrozenTable = POINTER(struct_frozen)1007>>> table = FrozenTable.in_dll(pythonapi, "_PyImport_FrozenBootstrap")1008>>>1009```10101011Поскольку `table` – это `pointer` на массив записей `struct_frozen`, мы можем выполнять итерацию по нему, но нужно убедиться, что цикл завершается, потому что указатели не имеют размера. Рано или поздно это, вероятно, приведет к краху из-за нарушения доступа или чему-то подобному, поэтому лучше выйти из цикла при достижении записи `NULL`:10121013```python1014>>> for item in table:1015...     if item.name is None:1016...         break1017...     print(item.name.decode("ascii"), item.size)1018...1019_frozen_importlib 317641020_frozen_importlib_external 414991021zipimport 123451022>>>1023```10241025Тот факт, что стандартный Python содержит замороженный модуль и замороженный пакет (обозначаемый отрицательным значением элемента `size`), малоизвестен; это используется только для тестирования. Попробуйте, например, с `import __hello__`.10261027### Неожиданности10281029В `ctypes` есть некоторые пограничные случаи, где можно ожидать чего-то иного, чем происходит на самом деле.10301031Рассмотрим следующий пример:10321033```python1034>>> from ctypes import *1035>>> class POINT(Structure):1036...     _fields_ = ("x", c_int), ("y", c_int)1037...1038>>> class RECT(Structure):1039...     _fields_ = ("a", POINT), ("b", POINT)1040...1041>>> p1 = POINT(1, 2)1042>>> p2 = POINT(3, 4)1043>>> rc = RECT(p1, p2)1044>>> print(rc.a.x, rc.a.y, rc.b.x, rc.b.y)10451 2 3 41046>>> # теперь поменять точки местами1047>>> rc.a, rc.b = rc.b, rc.a1048>>> print(rc.a.x, rc.a.y, rc.b.x, rc.b.y)10493 4 3 41050>>>1051```10521053Хм. Мы, безусловно, ожидали, что последний оператор выведет `3 4 1 2`. Что произошло? Вот шаги выполнения строки `rc.a, rc.b = rc.b, rc.a` выше:10541055```python1056>>> temp0, temp1 = rc.b, rc.a1057>>> rc.a = temp01058>>> rc.b = temp11059>>>1060```10611062Обратите внимание, что `temp0` и `temp1` – это объекты, все еще использующие внутренний буфер объекта `rc` выше. Таким образом, выполнение `rc.a = temp0` копирует содержимое буфера `temp0` в буфер `rc`. Это, в свою очередь, изменяет содержимое `temp1`. Поэтому последнее присваивание `rc.b = temp1` не дает ожидаемого эффекта.10631064Имейте в виду, что получение подобъектов из Structure, Unions и Arrays не *копирует* подобъект, а возвращает объект-обертку, обращающийся к базовому буферу корневого объекта.10651066Другой пример, который может вести себя иначе, чем ожидается:10671068```python1069>>> s = c_char_p()1070>>> s.value = b"abc def ghi"1071>>> s.value1072b'abc def ghi'1073>>> s.value is s.value1074False1075>>>1076```10771078> **Примечание**1079>1080> Объекты, созданные из [`c_char_p`](https://python-all.ru/3.16/library/ctypes.html#ctypes.c_char_p), могут иметь значение только в виде байтов или целых чисел.10811082Почему выводится `False`? Экземпляры ctypes – это объекты, содержащие блок памяти и несколько [дескрипторов](https://python-all.ru/3.16/glossary.html#term-descriptor), обращающихся к содержимому памяти. Сохранение объекта Python в блоке памяти не сохраняет сам объект, вместо этого сохраняется `contents` объекта. При повторном доступе к содержимому каждый раз создается новый объект Python!10831084### Типы данных переменного размера10851086`ctypes` предоставляет некоторую поддержку массивов и структур переменного размера.10871088Функция [`resize()`](https://python-all.ru/3.16/library/ctypes.html#ctypes.resize) может использоваться для изменения размера буфера памяти существующего объекта ctypes. Функция принимает объект в качестве первого аргумента и запрошенный размер в байтах в качестве второго аргумента. Блок памяти не может быть уменьшен меньше естественного блока памяти, заданного типом объекта; при попытке этого вызывается [`ValueError`](https://python-all.ru/3.16/library/exceptions.html#ValueError):10891090```python1091>>> short_array = (c_short * 4)()1092>>> print(sizeof(short_array))109381094>>> resize(short_array, 4)1095Traceback (most recent call last):1096    ...1097ValueError: minimum size is 81098>>> resize(short_array, 32)1099>>> sizeof(short_array)1100321101>>> sizeof(type(short_array))110281103>>>1104```11051106Это хорошо и замечательно, но как получить доступ к дополнительным элементам, содержащимся в этом массиве? Поскольку тип по-прежнему знает только о 4 элементах, при попытке доступа к другим элементам возникают ошибки:11071108```python1109>>> short_array[:]1110[0, 0, 0, 0]1111>>> short_array[7]1112Traceback (most recent call last):1113    ...1114IndexError: invalid index1115>>>1116```11171118Другой способ использования типов данных переменного размера с `ctypes` – воспользоваться динамической природой Python и (пере-)определять тип данных после того, как требуемый размер уже известен, в каждом конкретном случае.11191120## Справочник по ctypes11211122### Загрузка динамических библиотек11231124Существует несколько способов загрузки динамических библиотек в процесс Python. Один из способов – создать экземпляр [`CDLL`](https://python-all.ru/3.16/library/ctypes.html#ctypes.CDLL) или одного из его подклассов:11251126#### `class ctypes.CDLL(name, mode=DEFAULT_MODE, handle=None, use_errno=False, use_last_error=False, winmode=None)`11271128Представляет загруженную динамическую библиотеку.11291130Функции в этой библиотеке используют стандартное соглашение о вызовах C и предположительно возвращают int. [Глобальная блокировка интерпретатора Python](https://python-all.ru/3.16/glossary.html#term-global-interpreter-lock) освобождается перед вызовом любой функции, экспортируемой этими библиотеками, и захватывается снова после. Для другого поведения функций используйте подкласс: [`OleDLL`](https://python-all.ru/3.16/library/ctypes.html#ctypes.OleDLL), [`WinDLL`](https://python-all.ru/3.16/library/ctypes.html#ctypes.WinDLL) или [`PyDLL`](https://python-all.ru/3.16/library/ctypes.html#ctypes.PyDLL).11311132Если у вас есть существующий [`handle`](https://python-all.ru/3.16/library/ctypes.html#ctypes.CDLL._handle) на уже загруженную динамическую библиотеку, его можно передать в качестве аргумента *handle*, чтобы обернуть открытую библиотеку в новый объект `CDLL`. В этом случае *name* используется только для установки атрибута [`_name`](https://python-all.ru/3.16/library/ctypes.html#ctypes.CDLL._name), но может быть скорректирован и/или проверен.11331134Если *handle* равен `None`, то для загрузки библиотеки в процесс и получения её дескриптора используется функция *[dlopen(3)](https://python-all.ru/3.16/library/ctypes.html)* или [LoadLibraryExW](https://python-all.ru/3.16/library/ctypes.html) базовой платформы.11351136*name* – это путь к открываемой динамической библиотеке. Если *name* не содержит разделителя пути, библиотека находится способом, зависящим от платформы.11371138В Windows суффикс `.DLL` может отсутствовать. (Подробнее см. документацию [LoadLibraryExW](https://python-all.ru/3.16/library/ctypes.html).) Другие специфичные для платформы префиксы и суффиксы (например, `lib`, `.so`, `.dylib` или номера версий) должны присутствовать в *name*; они не добавляются автоматически. Дополнительную информацию см. в разделе [Поиск разделяемых библиотек](https://python-all.ru/3.16/library/ctypes.html#ctypes-finding-shared-libraries).11391140В системах, отличных от Windows, *name* может быть `None`. В этом случае `dlopen()` вызывается с `NULL`, что открывает главную программу как «библиотеку». (Некоторые системы делают то же самое, если *name* пуст; `None`/`NULL` более портативно.)11411142> **Особенность реализации CPython**1143>1144> Поскольку CPython слинкован с `libc`, `None` с *name* часто используется для доступа к стандартной библиотеке C:1145>1146> ```python1147> >>> printf = ctypes.CDLL(None).printf1148> >>> printf.argtypes = [ctypes.c_char_p]1149> >>> printf(b"hello\n")1150> hello1151> 61152> ```1153>1154> Для доступа к Python C API предпочтительнее использовать [`ctypes.pythonapi`](https://python-all.ru/3.16/library/ctypes.html#ctypes.pythonapi), который работает на разных платформах.11551156Параметр *mode* можно использовать для указания способа загрузки библиотеки. За подробностями обратитесь к man-странице *[dlopen(3)](https://python-all.ru/3.16/library/ctypes.html)*. В Windows *mode* игнорируется. В системах POSIX всегда добавляется RTLD\_NOW, и это не настраивается.11571158Параметр *use\_errno*, если установлен в true, включает механизм ctypes, который позволяет безопасно обращаться к системному номеру ошибки [`errno`](https://python-all.ru/3.16/library/errno.html#module-errno). `ctypes` хранит локальную для потока копию системной переменной `errno`; если вызывать внешние функции, созданные с помощью `use_errno=True`, то значение `errno` перед вызовом функции заменяется приватной копией ctypes, то же самое происходит сразу после вызова функции.11591160Функция [`ctypes.get_errno()`](https://python-all.ru/3.16/library/ctypes.html#ctypes.get_errno) возвращает значение приватной копии ctypes, а функция [`ctypes.set_errno()`](https://python-all.ru/3.16/library/ctypes.html#ctypes.set_errno) изменяет приватную копию ctypes на новое значение и возвращает предыдущее значение.11611162Параметр *use\_last\_error*, если установлен в true, включает тот же механизм для кода ошибки Windows, который управляется функциями Windows API [`GetLastError()`](https://python-all.ru/3.16/library/ctypes.html#ctypes.GetLastError) и `SetLastError()`; [`ctypes.get_last_error()`](https://python-all.ru/3.16/library/ctypes.html#ctypes.get_last_error) и [`ctypes.set_last_error()`](https://python-all.ru/3.16/library/ctypes.html#ctypes.set_last_error) используются для запроса и изменения приватной копии кода ошибки Windows в ctypes.11631164Параметр *winmode* используется в Windows для указания способа загрузки библиотеки (так как *mode* игнорируется). Он принимает любое значение, допустимое для параметра flags Win32 API [LoadLibraryExW](https://python-all.ru/3.16/library/ctypes.html). Если параметр опущен, по умолчанию используются флаги, обеспечивающие наиболее безопасную загрузку DLL, что позволяет избежать таких проблем, как перехват DLL. Передача полного пути к DLL – самый надёжный способ гарантировать загрузку правильной библиотеки и её зависимостей.11651166В Windows создание экземпляра `CDLL` может завершиться неудачей, даже если имя DLL существует. Если зависимая DLL загружаемой DLL не найдена, возникает ошибка [`OSError`](https://python-all.ru/3.16/library/exceptions.html#OSError) с сообщением *«\[WinError 126\] Указанный модуль не найден».* Это сообщение об ошибке не содержит имени отсутствующей DLL, поскольку Windows API не возвращает эту информацию, что затрудняет диагностику. Чтобы устранить эту ошибку и определить, какая DLL не найдена, необходимо найти список зависимых DLL и выяснить, какая из них отсутствует, с помощью инструментов отладки и трассировки Windows.11671168> **См. также**1169>1170> [Инструмент Microsoft DUMPBIN](https://python-all.ru/3.16/library/ctypes.html) – инструмент для поиска зависимостей DLL.11711172Изменено в версии 3.8: Добавлен параметр *winmode*.11731174Изменено в версии 3.12: Параметр *name* теперь может быть [объектом, подобным пути](https://python-all.ru/3.16/glossary.html#term-path-like-object).11751176Экземпляры этого класса не имеют публичных методов. Функции, экспортируемые разделяемой библиотекой, можно получить как атрибуты или по индексу. Обратите внимание, что обращение к функции через атрибут кэширует результат, и поэтому повторное обращение каждый раз возвращает один и тот же объект. С другой стороны, обращение по индексу возвращает каждый раз новый объект:11771178```python1179>>> from ctypes import CDLL1180>>> libc = CDLL("libc.so.6")  # В Linux1181>>> libc.time == libc.time1182True1183>>> libc['time'] == libc['time']1184False1185```11861187Доступны следующие публичные атрибуты. Их имена начинаются с символа подчёркивания, чтобы не пересекаться с именами экспортируемых функций:11881189#### `_handle`11901191Системный дескриптор, используемый для доступа к библиотеке.11921193#### `_name`11941195Имя библиотеки, переданное в конструктор.11961197#### `class ctypes.OleDLL`11981199См. [`CDLL`](https://python-all.ru/3.16/library/ctypes.html#ctypes.CDLL), родительский класс, для общей информации.12001201Функции в этой библиотеке используют соглашение о вызовах `stdcall` и считаются возвращающими код [`HRESULT`](https://python-all.ru/3.16/library/ctypes.html#ctypes.HRESULT), специфичный для Windows. Значения `HRESULT` содержат информацию о том, завершился ли вызов функции неудачей или успехом, а также дополнительный код ошибки. Если возвращаемое значение сигнализирует об ошибке, автоматически вызывается исключение [`OSError`](https://python-all.ru/3.16/library/exceptions.html#OSError).12021203[Доступность](https://python-all.ru/3.16/library/intro.html#availability): Windows12041205Изменено в версии 3.3: [`WindowsError`](https://python-all.ru/3.16/library/exceptions.html#WindowsError) раньше вызывалось, а теперь является псевдонимом [`OSError`](https://python-all.ru/3.16/library/exceptions.html#OSError).12061207#### `class ctypes.WinDLL`12081209См. [`CDLL`](https://python-all.ru/3.16/library/ctypes.html#ctypes.CDLL), родительский класс, для общей информации.12101211Функции в этих библиотеках используют соглашение о вызовах `stdcall` и по умолчанию считаются возвращающими int.12121213[Доступность](https://python-all.ru/3.16/library/intro.html#availability): Windows12141215#### `class ctypes.PyDLL`12161217См. [`CDLL`](https://python-all.ru/3.16/library/ctypes.html#ctypes.CDLL), родительский класс, для общей информации.12181219Когда вызываются функции этой библиотеки, GIL Python *не* освобождается во время вызова, и после выполнения функции проверяется флаг ошибки Python. Если флаг ошибки установлен, вызывается исключение Python.12201221Таким образом, это полезно только для прямого вызова функций C API Python.12221223#### `ctypes.RTLD_GLOBAL`12241225Флаг, используемый в качестве параметра *mode*. На платформах, где этот флаг недоступен, он определён как целочисленный ноль.12261227#### `ctypes.RTLD_LOCAL`12281229Флаг, используемый в качестве параметра *mode*. На платформах, где он недоступен, он совпадает с *RTLD\_GLOBAL*.12301231#### `ctypes.DEFAULT_MODE`12321233Режим по умолчанию, используемый для загрузки разделяемых библиотек. На OSX 10.3 это *RTLD\_GLOBAL*, в противном случае он совпадает с *RTLD\_LOCAL*.12341235Разделяемые библиотеки также можно загружать с помощью одного из готовых объектов, которые являются экземплярами класса [`LibraryLoader`](https://python-all.ru/3.16/library/ctypes.html#ctypes.LibraryLoader), либо вызывая метод [`LoadLibrary()`](https://python-all.ru/3.16/library/ctypes.html#ctypes.LibraryLoader.LoadLibrary), либо получая библиотеку как атрибут экземпляра загрузчика.12361237#### `class ctypes.LibraryLoader(dlltype)`12381239Класс, который загружает разделяемые библиотеки. *dlltype* должен быть одним из типов [`CDLL`](https://python-all.ru/3.16/library/ctypes.html#ctypes.CDLL), [`PyDLL`](https://python-all.ru/3.16/library/ctypes.html#ctypes.PyDLL), [`WinDLL`](https://python-all.ru/3.16/library/ctypes.html#ctypes.WinDLL) или [`OleDLL`](https://python-all.ru/3.16/library/ctypes.html#ctypes.OleDLL).12401241`__getattr__()` обладает особым поведением: он позволяет загружать разделяемую библиотеку, обращаясь к ней как к атрибуту экземпляра загрузчика библиотек. Результат кэшируется, поэтому повторные обращения к атрибуту каждый раз возвращают одну и ту же библиотеку.12421243#### `LoadLibrary(name)`12441245Загружает разделяемую библиотеку в процесс и возвращает её. Этот метод всегда возвращает новый экземпляр библиотеки.12461247Доступны следующие готовые загрузчики библиотек:12481249> #### `ctypes.cdll`1250>1251> Создаёт экземпляры [`CDLL`](https://python-all.ru/3.16/library/ctypes.html#ctypes.CDLL).1252>1253> #### `ctypes.windll`1254>1255> Создаёт экземпляры [`WinDLL`](https://python-all.ru/3.16/library/ctypes.html#ctypes.WinDLL).1256>1257> [Доступность](https://python-all.ru/3.16/library/intro.html#availability): Windows1258>1259> #### `ctypes.oledll`1260>1261> Создаёт экземпляры [`OleDLL`](https://python-all.ru/3.16/library/ctypes.html#ctypes.OleDLL).1262>1263> [Доступность](https://python-all.ru/3.16/library/intro.html#availability): Windows1264>1265> #### `ctypes.pydll`1266>1267> Создаёт экземпляры [`PyDLL`](https://python-all.ru/3.16/library/ctypes.html#ctypes.PyDLL).1268>1269> #### `ctypes.pythonapi`1270>1271> Экземпляр [`PyDLL`](https://python-all.ru/3.16/library/ctypes.html#ctypes.PyDLL), который предоставляет функции Python C API в виде атрибутов. Обратите внимание: предполагается, что все эти функции возвращают C int, что, конечно, не всегда верно, поэтому необходимо назначить правильный атрибут `restype`, чтобы использовать эти функции.12721273Загрузка библиотеки через любой из этих объектов вызывает [событие аудита](https://python-all.ru/3.16/library/sys.html#auditing) `ctypes.dlopen` со строковым аргументом `name` – именем, используемым для загрузки библиотеки.12741275Доступ к функции загруженной библиотеки вызывает событие аудита `ctypes.dlsym` с аргументами `library` (объект библиотеки) и `name` (имя символа в виде строки или целого числа).12761277В случаях, когда доступен только дескриптор библиотеки, а не сам объект, обращение к функции вызывает событие аудита `ctypes.dlsym/handle` с аргументами `handle` (сырой дескриптор библиотеки) и `name`.12781279### Поиск разделяемых библиотек12801281При программировании на компилируемом языке общие библиотеки используются на этапах компиляции/линковки программы и при её выполнении. Программист задаёт короткое имя; затем C-компилятор, компоновщик и загрузчик динамических библиотек времени выполнения взаимодействуют платформозависимым образом, чтобы найти имя файла загружаемой библиотеки.12821283Хотя отображение коротких имён в имена файлов не предоставляется платформами единообразно, модуль `ctypes.util` предоставляет функцию `find_library()`, которая пытается его воспроизвести. Однако из-за необходимости обратной совместимости сложно адаптировать её поведение для новых платформ и конфигураций, поэтому функция [мягко устарела](https://python-all.ru/3.16/glossary.html#term-soft-deprecated).12841285При оборачивании общей библиотеки с помощью `ctypes` рекомендуется определять имя общей библиотеки на этапе разработки и жёстко прописывать его в модуле-обёртке вместо использования `find_library()` для поиска библиотеки во время выполнения. Также стоит добавить опцию конфигурации или переменную окружения, позволяющие пользователям выбирать библиотеку, и затем, возможно, использовать `find_library()` как значение по умолчанию или запасной вариант.12861287#### `ctypes.util.find_library(name)`12881289Пытается найти библиотеку и возвращает путь к ней.12901291*name* – это «короткое» имя библиотеки без префикса наподобие `lib`, суффикса вроде `.so`, `.dylib` или номера версии. (Такая форма используется для опции компоновщика POSIX `-l`.) Результат возвращается в формате, подходящем для передачи в [`CDLL`](https://python-all.ru/3.16/library/ctypes.html#ctypes.CDLL).12921293Если библиотеку не удалось найти, возвращается `None`.12941295Точное поведение зависит от системы и *не гарантируется*, что оно будет соответствовать поведению компилятора, компоновщика и загрузчика, используемых для (или с) Python. Рекомендуется использовать эту функцию только как значение по умолчанию или запасной вариант.12961297[Мягко устарела](https://python-all.ru/3.16/glossary.html#term-soft-deprecated) с версии 3.15: Эта функция сохранена для использования в случаях, где она работает, но не предполагается, что она будет обновляться для дополнительных платформ и конфигураций.12981299В Linux `find_library()` пытается запустить внешние программы (`/sbin/ldconfig`, `gcc`, `objdump` и `ld`), чтобы найти файл библиотеки. Если вывод этих программ не соответствует динамическому компоновщику, используемому Python, результат этой функции может ввести в заблуждение.13001301Изменено в версии 3.6: В Linux значение переменной окружения `LD_LIBRARY_PATH` используется при поиске библиотек, если библиотеку не удаётся найти другими способами.13021303Вот несколько примеров:13041305```python1306>>> from ctypes.util import find_library1307>>> find_library("m")1308'libm.so.6'1309>>> find_library("c")1310'libc.so.6'1311>>> find_library("bz2")1312'libbz2.so.1.0'1313>>>1314```13151316В macOS и Android `find_library()` использует стандартные схемы именования и пути системы для поиска библиотеки и в случае успеха возвращает полный путь:13171318```python1319>>> from ctypes.util import find_library1320>>> find_library("c")1321'/usr/lib/libc.dylib'1322>>> find_library("m")1323'/usr/lib/libm.dylib'1324>>> find_library("bz2")1325'/usr/lib/libbz2.dylib'1326>>> find_library("AGL")1327'/System/Library/Frameworks/AGL.framework/AGL'1328>>>1329```13301331В Windows `find_library()` выполняет поиск по системному пути поиска и возвращает полный путь, но поскольку нет предопределённой схемы именования, вызов наподобие `find_library("c")` завершится неудачей и вернёт `None`.13321333#### `ctypes.util.find_msvcrt()`13341335Возвращает имя файла библиотеки времени выполнения VC, используемой Python и модулями расширения.13361337Если имя библиотеки не удаётся определить, возвращается `None`. Примечательно, что это происходит для последних версий библиотеки времени выполнения VC, которые невозможно загрузить напрямую.13381339Если необходимо освободить память, выделенную, например, модулем расширения с помощью вызова `free(void *)`, важно использовать функцию из той же библиотеки, которая выделила память.13401341[Доступность](https://python-all.ru/3.16/library/intro.html#availability): Windows13421343### Список загруженных динамических библиотек13441345При написании кода, который зависит от кода, загруженного из динамических библиотек, может быть полезно знать, какие динамические библиотеки уже загружены в текущий процесс.13461347Модуль `ctypes.util` предоставляет функцию [`dllist()`](https://python-all.ru/3.16/library/ctypes.html#ctypes.util.dllist), которая вызывает различные API, предоставляемые разными платформами, чтобы помочь определить, какие динамические библиотеки уже загружены в текущий процесс.13481349Точный вывод этой функции зависит от системы. На большинстве платформ первая запись этого списка представляет сам текущий процесс, который может быть пустой строкой. Например, в Linux на glibc возвращаемое значение может выглядеть так:13501351```python1352>>> from ctypes.util import dllist1353>>> dllist()1354['', 'linux-vdso.so.1', '/lib/x86_64-linux-gnu/libm.so.6', '/lib/x86_64-linux-gnu/libc.so.6', ... ]1355```13561357### Внешние функции13581359Как было объяснено в предыдущем разделе, к внешним функциям можно обращаться как к атрибутам загруженных общих библиотек. Созданные таким образом объекты функций по умолчанию принимают любое количество аргументов, принимают любые экземпляры данных ctypes в качестве аргументов и возвращают тип результата по умолчанию, заданный загрузчиком библиотеки.13601361Они являются экземплярами закрытого локального класса `_FuncPtr` (не доступного в `ctypes`), который наследуется от закрытого класса [`_CFuncPtr`](https://python-all.ru/3.16/library/ctypes.html#ctypes._CFuncPtr):13621363```pycon1364>>> import ctypes1365>>> lib = ctypes.CDLL(None)1366>>> issubclass(lib._FuncPtr, ctypes._CFuncPtr)1367True1368>>> lib._FuncPtr is ctypes._CFuncPtr1369False1370```13711372#### `class ctypes._CFuncPtr`13731374Базовый класс для внешних функций, вызываемых из C.13751376Экземпляры внешних функций также являются C-совместимыми типами данных; они представляют указатели на функции C.13771378Это поведение можно настроить, присвоив значения специальным атрибутам объекта внешней функции.13791380#### `restype`13811382Назначьте тип ctypes, чтобы указать тип результата внешней функции. Используйте `None` для void – функции, не возвращающей ничего.13831384Можно назначить вызываемый объект Python, который не является типом ctypes; в этом случае предполагается, что функция возвращает C int, и вызываемый объект будет вызван с этим целым числом, что позволяет выполнить дополнительную обработку или проверку ошибок. Использование этого подхода устарело; для более гибкой последующей обработки или проверки ошибок используйте тип данных ctypes в качестве `restype` и назначьте вызываемый объект атрибуту [`errcheck`](https://python-all.ru/3.16/library/ctypes.html#ctypes._CFuncPtr.errcheck).13851386#### `argtypes`13871388Назначьте кортеж типов ctypes, чтобы указать типы аргументов, которые принимает функция. Функции, использующие соглашение о вызове `stdcall`, могут быть вызваны только с тем же количеством аргументов, что и длина этого кортежа; функции, использующие C соглашение о вызове, также принимают дополнительные неопределённые аргументы.13891390При вызове внешней функции каждый фактический аргумент передаётся методу класса [`from_param()`](https://python-all.ru/3.16/library/ctypes.html#ctypes._CData.from_param) элементов кортежа [`argtypes`](https://python-all.ru/3.16/library/ctypes.html#ctypes._CFuncPtr.argtypes); этот метод позволяет адаптировать фактический аргумент к объекту, который принимает внешняя функция. Например, элемент [`c_char_p`](https://python-all.ru/3.16/library/ctypes.html#ctypes.c_char_p) в кортеже `argtypes` преобразует строку, переданную в качестве аргумента, в объект bytes, используя правила преобразования ctypes.13911392Новое: теперь можно помещать в argtypes элементы, которые не являются типами ctypes, но каждый элемент должен иметь метод [`from_param()`](https://python-all.ru/3.16/library/ctypes.html#ctypes._CData.from_param), возвращающий значение, пригодное в качестве аргумента (целое число, строка, экземпляр ctypes). Это позволяет определять адаптеры, которые могут адаптировать пользовательские объекты в качестве параметров функции.13931394#### `errcheck`13951396Этому атрибуту присваивается функция Python или другой вызываемый объект. Вызываемый объект будет вызван с тремя и более аргументами:13971398#### `callable(result, func, arguments)`13991400*result* – это то, что возвращает внешняя функция, как указано атрибутом `restype`.14011402*func* – это сам объект внешней функции; это позволяет повторно использовать один и тот же вызываемый объект для проверки или последующей обработки результатов нескольких функций.14031404*arguments* – это кортеж, содержащий параметры, переданные вызову функции; это позволяет специализировать поведение на основе используемых аргументов.14051406Объект, возвращаемый этой функцией, будет возвращён из вызова внешней функции, но он также может проверить значение результата и возбудить исключение, если вызов внешней функции завершился неудачей.14071408В Windows, когда вызов внешней функции вызывает системное исключение (например, из-за нарушения доступа), оно перехватывается и заменяется подходящим исключением Python. Кроме того, возбуждается событие аудита `ctypes.set_exception` с аргументом `code`, позволяя обработчику аудита заменить исключение своим собственным.14091410Некоторые способы вызова внешних функций, а также некоторые функции этого модуля могут возбуждать событие аудита `ctypes.call_function` с аргументами `function pointer` и `arguments`.14111412### Прототипы функций14131414Внешние функции также можно создавать, создавая экземпляры прототипов функций. Прототипы функций похожи на прототипы функций в C: они описывают функцию (тип возврата, типы аргументов, соглашение о вызове), не определяя реализацию. Фабричные функции необходимо вызывать с желаемым типом результата и типами аргументов функции; их можно использовать как фабрики декораторов и, следовательно, применять к функциям через синтаксис `@wrapper`. Примеры см. в [функции обратного вызова](https://python-all.ru/3.16/library/ctypes.html#ctypes-callback-functions).14151416#### `ctypes.CFUNCTYPE(restype, *argtypes, use_errno=False, use_last_error=False)`14171418Созданный прототип функции создаёт функции, использующие стандартное соглашение о вызове C. Функция освобождает GIL во время вызова. Если *use\_errno* установлен в true, приватная копия переменной [`errno`](https://python-all.ru/3.16/library/errno.html#module-errno) ctypes обменивается с реальным значением `errno` до и после вызова; *use\_last\_error* делает то же самое для кода ошибки Windows.14191420#### `ctypes.WINFUNCTYPE(restype, *argtypes, use_errno=False, use_last_error=False)`14211422Созданный прототип функции создаёт функции, использующие соглашение о вызове `stdcall`. Функция освобождает GIL во время вызова. *use\_errno* и *use\_last\_error* имеют то же значение, что и выше.14231424[Доступность](https://python-all.ru/3.16/library/intro.html#availability): Windows14251426#### `ctypes.PYFUNCTYPE(restype, *argtypes)`14271428Созданный прототип функции создаёт функции, использующие соглашение о вызове Python. Функция *не* освобождает GIL во время вызова.14291430Прототипы функций, созданные этими фабричными функциями, могут быть созданы различными способами, в зависимости от типа и количества параметров в вызове:14311432#### `prototype(address)`14331434Возвращает внешнюю функцию по указанному адресу, который должен быть целым числом.14351436#### `prototype(callable)`14371438Создаёт вызываемую функцию C (функцию обратного вызова) из *вызываемого объекта* Python.14391440#### `prototype(func_spec[, paramflags])`14411442Возвращает внешнюю функцию, экспортируемую общей библиотекой. *func\_spec* должен быть 2-кортежем `(name_or_ordinal, library)`. Первый элемент – это имя экспортируемой функции в виде строки или порядковый номер экспортируемой функции в виде небольшого целого числа. Второй элемент – это экземпляр общей библиотеки.14431444#### `prototype(vtbl_index, name[, paramflags[, iid]])`14451446Возвращает внешнюю функцию, которая будет вызывать метод COM. *vtbl\_index* – это индекс в таблице виртуальных функций, небольшое неотрицательное целое число. *name* – это имя метода COM. *iid* – необязательный указатель на идентификатор интерфейса, используемый в расширенном отчёте об ошибках.14471448Если *iid* не указан, при сбое вызова метода COM возбуждается [`OSError`](https://python-all.ru/3.16/library/exceptions.html#OSError). Если *iid* указан, вместо этого возбуждается [`COMError`](https://python-all.ru/3.16/library/ctypes.html#ctypes.COMError).14491450Методы COM используют специальное соглашение о вызове: в качестве первого аргумента требуется указатель на интерфейс COM, помимо тех параметров, которые указаны в кортеже `argtypes`.14511452[Доступность](https://python-all.ru/3.16/library/intro.html#availability): Windows14531454Необязательный параметр *paramflags* создаёт обёртки внешних функций с гораздо большей функциональностью, чем описано выше.14551456*paramflags* должен быть кортежем той же длины, что и [`argtypes`](https://python-all.ru/3.16/library/ctypes.html#ctypes._CFuncPtr.argtypes).14571458Каждый элемент этого кортежа содержит дополнительную информацию о параметре; он должен быть кортежем, содержащим один, два или три элемента.14591460Первый элемент – целое число, содержащее комбинацию флагов направления для параметра:14611462> **1**1463>1464> Задаёт входной параметр функции.1465>1466> **2**1467>1468> Выходной параметр. Внешняя функция заполняет значение.1469>1470> **4**1471>1472> Входной параметр, по умолчанию равный нулю.14731474Необязательный второй элемент – имя параметра в виде строки. Если он указан, внешнюю функцию можно вызывать с именованными параметрами.14751476Необязательный третий элемент – значение по умолчанию для этого параметра.14771478Следующий пример демонстрирует, как обернуть функцию Windows `MessageBoxW` так, чтобы она поддерживала параметры по умолчанию и именованные аргументы. Объявление на C из заголовочного файла Windows выглядит так:14791480```python1481WINUSERAPI int WINAPI1482MessageBoxW(1483    HWND hWnd,1484    LPCWSTR lpText,1485    LPCWSTR lpCaption,1486    UINT uType);1487```14881489Вот обёртка с помощью `ctypes`:14901491```python1492>>> from ctypes import c_int, WINFUNCTYPE, windll1493>>> from ctypes.wintypes import HWND, LPCWSTR, UINT1494>>> prototype = WINFUNCTYPE(c_int, HWND, LPCWSTR, LPCWSTR, UINT)1495>>> paramflags = (1, "hwnd", 0), (1, "text", "Hi"), (1, "caption", "Hello from ctypes"), (1, "flags", 0)1496>>> MessageBox = prototype(("MessageBoxW", windll.user32), paramflags)1497```14981499Теперь внешнюю функцию `MessageBox` можно вызывать следующими способами:15001501```python1502>>> MessageBox()1503>>> MessageBox(text="Spam, spam, spam")1504>>> MessageBox(flags=2, text="foo bar")1505```15061507Второй пример демонстрирует выходные параметры. Функция win32 `GetWindowRect` получает размеры указанного окна, копируя их в структуру `RECT`, которую должен предоставить вызывающий. Вот объявление на C:15081509```python1510WINUSERAPI BOOL WINAPI1511GetWindowRect(1512     HWND hWnd,1513     LPRECT lpRect);1514```15151516Вот обёртка с помощью `ctypes`:15171518```python1519>>> from ctypes import POINTER, WINFUNCTYPE, windll, WinError1520>>> from ctypes.wintypes import BOOL, HWND, RECT1521>>> prototype = WINFUNCTYPE(BOOL, HWND, POINTER(RECT))1522>>> paramflags = (1, "hwnd"), (2, "lprect")1523>>> GetWindowRect = prototype(("GetWindowRect", windll.user32), paramflags)1524>>>1525```15261527Функции с выходными параметрами автоматически возвращают значение выходного параметра, если он один, или кортеж значений выходных параметров, если их несколько; таким образом, при вызове функция GetWindowRect теперь возвращает экземпляр RECT.15281529Выходные параметры можно комбинировать с протоколом [`errcheck`](https://python-all.ru/3.16/library/ctypes.html#ctypes._CFuncPtr.errcheck) для дополнительной обработки выходных данных и проверки ошибок. Функция win32 API `GetWindowRect` возвращает `BOOL`, сигнализируя об успехе или неудаче, поэтому эта функция может выполнять проверку ошибок и возбуждать исключение при сбое вызова API:15301531```python1532>>> def errcheck(result, func, args):1533...     if not result:1534...         raise WinError()1535...     return args1536...1537>>> GetWindowRect.errcheck = errcheck1538>>>1539```15401541Если функция [`errcheck`](https://python-all.ru/3.16/library/ctypes.html#ctypes._CFuncPtr.errcheck) возвращает полученный кортеж аргументов без изменений, `ctypes` продолжает обычную обработку выходных параметров. Если же требуется вернуть кортеж координат окна вместо экземпляра `RECT`, можно извлечь поля в функции и вернуть их – тогда обычная обработка выполняться не будет:15421543```python1544>>> def errcheck(result, func, args):1545...     if not result:1546...         raise WinError()1547...     rc = args[1]1548...     return rc.left, rc.top, rc.bottom, rc.right1549...1550>>> GetWindowRect.errcheck = errcheck1551>>>1552```15531554### Вспомогательные функции15551556#### `ctypes.addressof(obj)`15571558Возвращает адрес буфера памяти в виде целого числа. *obj* должен быть экземпляром типа ctypes.15591560Вызывает [событие аудита](https://python-all.ru/3.16/library/sys.html#auditing) `ctypes.addressof` с аргументом `obj`.15611562#### `ctypes.alignment(obj_or_type)`15631564Возвращает требования к выравниванию для типа ctypes. *obj\_or\_type* должен быть типом ctypes или его экземпляром.15651566#### `ctypes.byref(obj[, offset])`15671568Возвращает легковесный указатель на *obj*, который должен быть экземпляром типа ctypes. Параметр *offset* по умолчанию равен нулю и должен быть целым числом, которое будет добавлено к внутреннему значению указателя.15691570`byref(obj, offset)` соответствует следующему коду на C:15711572```python1573(((char *)&obj) + offset)1574```15751576Возвращаемый объект можно использовать только как параметр вызова внешней функции. Он ведёт себя аналогично `pointer(obj)`, но создаётся гораздо быстрее.15771578#### `ctypes.CopyComPointer(src, dst)`15791580Копирует COM-указатель из *src* в *dst* и возвращает значение `HRESULT`, специфичное для Windows.15811582Если *src* не равен `NULL`, вызывается его метод `AddRef`, увеличивающий счётчик ссылок.15831584Напротив, счётчик ссылок *dst* не уменьшается перед присвоением нового значения. Если *dst* не равен `NULL`, вызывающий обязан уменьшить счётчик ссылок, вызвав при необходимости его метод `Release`.15851586[Доступность](https://python-all.ru/3.16/library/intro.html#availability): Windows15871588Добавлено в версии 3.14.15891590#### `ctypes.cast(obj, type)`15911592Эта функция аналогична оператору приведения типов в C. Она возвращает новый экземпляр *type*, указывающий на тот же блок памяти, что и *obj*. *type* должен быть типом-указателем, а *obj* – объектом, который можно интерпретировать как указатель.15931594#### `ctypes.create_string_buffer(init, size=None)`15951596#### `ctypes.create_string_buffer(size)`15971598Эта функция создаёт изменяемый символьный буфер. Возвращаемый объект представляет собой массив ctypes из [`c_char`](https://python-all.ru/3.16/library/ctypes.html#ctypes.c_char).15991600Если *size* указан (и не равен `None`), он должен быть [`int`](https://python-all.ru/3.16/library/functions.html#int). Он задаёт размер возвращаемого массива.16011602Если аргумент *init* указан, он должен быть [`bytes`](https://python-all.ru/3.16/library/stdtypes.html#bytes). Он используется для инициализации элементов массива. Байты, не инициализированные таким образом, устанавливаются в ноль (NUL).16031604Если *size* не указан (или равен `None`), буфер создаётся на один элемент больше, чем *init*, что фактически добавляет завершающий NUL.16051606Если указаны оба аргумента, *size* не должен быть меньше `len(init)`.16071608> **Предупреждение**1609>1610> Если *size* равен `len(init)`, завершающий NUL не добавляется. Не рассматривайте такой буфер как C-строку.16111612Например:16131614```python1615>>> bytes(create_string_buffer(2))1616b'\x00\x00'1617>>> bytes(create_string_buffer(b'ab'))1618b'ab\x00'1619>>> bytes(create_string_buffer(b'ab', 2))1620b'ab'1621>>> bytes(create_string_buffer(b'ab', 4))1622b'ab\x00\x00'1623>>> bytes(create_string_buffer(b'abcdef', 2))1624Traceback (most recent call last):1625   ...1626ValueError: byte string too long1627```16281629Возбуждает [событие аудита](https://python-all.ru/3.16/library/sys.html#auditing) `ctypes.create_string_buffer` с аргументами `init`, `size`.16301631#### `ctypes.create_unicode_buffer(init, size=None)`16321633#### `ctypes.create_unicode_buffer(size)`16341635Эта функция создаёт изменяемый буфер символов Unicode. Возвращаемый объект представляет собой массив ctypes из [`c_wchar`](https://python-all.ru/3.16/library/ctypes.html#ctypes.c_wchar).16361637Функция принимает те же аргументы, что и [`create_string_buffer()`](https://python-all.ru/3.16/library/ctypes.html#ctypes.create_string_buffer), за исключением того, что *init* должен быть строкой, а *size* подсчитывает [`c_wchar`](https://python-all.ru/3.16/library/ctypes.html#ctypes.c_wchar).16381639Возбуждает [событие аудита](https://python-all.ru/3.16/library/sys.html#auditing) `ctypes.create_unicode_buffer` с аргументами `init`, `size`.16401641#### `ctypes.DllCanUnloadNow()`16421643Эта функция является перехватчиком, который позволяет реализовывать внутрипроцессные COM-серверы с помощью ctypes. Она вызывается из функции DllCanUnloadNow, экспортируемой DLL расширения \_ctypes.16441645[Доступность](https://python-all.ru/3.16/library/intro.html#availability): Windows16461647#### `ctypes.DllGetClassObject()`16481649Эта функция является перехватчиком, который позволяет реализовывать внутрипроцессные COM-серверы с помощью ctypes. Она вызывается из функции DllGetClassObject, экспортируемой DLL расширения `_ctypes`.16501651[Доступность](https://python-all.ru/3.16/library/intro.html#availability): Windows16521653#### `ctypes.util.dllist()`16541655Пытается предоставить список путей разделяемых библиотек, загруженных в текущий процесс. Эти пути никак не нормализованы и не обработаны. Функция может возбудить [`OSError`](https://python-all.ru/3.16/library/exceptions.html#OSError), если системные API платформы завершатся ошибкой. Точное поведение зависит от системы.16561657На большинстве платформ первый элемент списка представляет текущий исполняемый файл. Он может быть пустой строкой.16581659[Доступность](https://python-all.ru/3.16/library/intro.html#availability): Windows, macOS, iOS, glibc, BSD libc, musl16601661Добавлено в версии 3.14.16621663#### `ctypes.FormatError([code])`16641665Возвращает текстовое описание кода ошибки *code*. Если код ошибки не указан, используется код последней ошибки путём вызова функции Windows API [`GetLastError()`](https://python-all.ru/3.16/library/ctypes.html#ctypes.GetLastError).16661667[Доступность](https://python-all.ru/3.16/library/intro.html#availability): Windows16681669#### `ctypes.GetLastError()`16701671Возвращает последний код ошибки, установленный Windows в вызывающем потоке. Эта функция напрямую вызывает `GetLastError()` Windows, а не возвращает приватную копию кода ошибки из ctypes.16721673[Доступность](https://python-all.ru/3.16/library/intro.html#availability): Windows16741675#### `ctypes.get_errno()`16761677Возвращает текущее значение приватной копии ctypes для системной переменной [`errno`](https://python-all.ru/3.16/library/errno.html#module-errno) в вызывающем потоке.16781679Возбуждает [событие аудита](https://python-all.ru/3.16/library/sys.html#auditing) `ctypes.get_errno` без аргументов.16801681#### `ctypes.get_last_error()`16821683Возвращает текущее значение приватной копии ctypes для системной переменной `LastError` в вызывающем потоке.16841685[Доступность](https://python-all.ru/3.16/library/intro.html#availability): Windows16861687Возбуждает [событие аудита](https://python-all.ru/3.16/library/sys.html#auditing) `ctypes.get_last_error` без аргументов.16881689#### `ctypes.memmove(dst, src, count)`16901691Аналогична стандартной библиотечной функции C memmove: копирует *count* байт из *src* в *dst*. *dst* и *src* должны быть целыми числами или экземплярами ctypes, которые можно преобразовать в указатели.16921693#### `ctypes.memset(dst, c, count)`16941695Аналогична стандартной библиотечной функции C memset: заполняет блок памяти по адресу *dst* *count* байтами значения *c*. *dst* должно быть целым числом, задающим адрес, или экземпляром ctypes.16961697#### `ctypes.POINTER(type, /)`16981699Создаёт или возвращает тип указателя ctypes. Типы указателей кэшируются и повторно используются внутри, поэтому многократный вызов этой функции не нагружает систему. *type* должен быть типом ctypes.17001701**Детали реализации CPython:** Результирующий тип указателя кэшируется в атрибуте `__pointer_type__` типа *type*. Можно задать этот атрибут до первого вызова `POINTER`, чтобы установить пользовательский тип указателя. Однако этого делать не рекомендуется: вручную создать подходящий тип указателя сложно, не опираясь на детали реализации, которые могут измениться в будущих версиях Python.17021703#### `ctypes.pointer(obj, /)`17041705Создаёт новый экземпляр указателя, указывающий на *obj*. Возвращаемый объект имеет тип `POINTER(type(obj))`.17061707Примечание: Если требуется просто передать указатель на объект в вызов внешней функции, следует использовать `byref(obj)`, что намного быстрее.17081709#### `ctypes.resize(obj, size)`17101711Эта функция изменяет размер внутреннего буфера памяти *obj*, который должен быть экземпляром типа ctypes. Уменьшить буфер ниже собственного размера типа объекта, заданного `sizeof(type(obj))`, невозможно, но увеличить буфер – можно.17121713#### `ctypes.set_errno(value)`17141715Устанавливает текущее значение приватной копии ctypes для системной переменной [`errno`](https://python-all.ru/3.16/library/errno.html#module-errno) в вызывающем потоке в *value* и возвращает предыдущее значение.17161717Вызывает [событие аудита](https://python-all.ru/3.16/library/sys.html#auditing) `ctypes.set_errno` с аргументом `errno`.17181719#### `ctypes.set_last_error(value)`17201721Устанавливает текущее значение приватной копии ctypes для системной переменной `LastError` в вызывающем потоке в *value* и возвращает предыдущее значение.17221723[Доступность](https://python-all.ru/3.16/library/intro.html#availability): Windows17241725Вызывает [событие аудита](https://python-all.ru/3.16/library/sys.html#auditing) `ctypes.set_last_error` с аргументом `error`.17261727#### `ctypes.sizeof(obj_or_type)`17281729Возвращает размер в байтах буфера памяти типа или экземпляра ctypes. Делает то же, что и оператор C `sizeof`.17301731#### `ctypes.string_at(ptr, size=-1)`17321733Возвращает байтовую строку по адресу *void \*ptr*. Если задан *size*, он используется как размер, иначе строка считается завершающейся нулевым байтом.17341735Возбуждает [событие аудита](https://python-all.ru/3.16/library/sys.html#auditing) `ctypes.string_at` с аргументами `ptr`, `size`.17361737#### `ctypes.WinError(code=None, descr=None)`17381739Создаёт экземпляр [`OSError`](https://python-all.ru/3.16/library/exceptions.html#OSError). Если *code* не указан, вызывается [`GetLastError()`](https://python-all.ru/3.16/library/ctypes.html#ctypes.GetLastError) для определения кода ошибки. Если *descr* не указан, вызывается [`FormatError()`](https://python-all.ru/3.16/library/ctypes.html#ctypes.FormatError) для получения текстового описания ошибки.17401741[Доступность](https://python-all.ru/3.16/library/intro.html#availability): Windows17421743Изменено в версии 3.3: Ранее создавался экземпляр [`WindowsError`](https://python-all.ru/3.16/library/exceptions.html#WindowsError), который теперь является псевдонимом [`OSError`](https://python-all.ru/3.16/library/exceptions.html#OSError).17441745#### `ctypes.wstring_at(ptr, size=-1)`17461747Возвращает строку широких символов по адресу *void \*ptr*. Если указан *size*, он используется как количество символов строки, в противном случае строка считается завершающейся нулевым символом.17481749Возбуждает [событие аудита](https://python-all.ru/3.16/library/sys.html#auditing) `ctypes.wstring_at` с аргументами `ptr`, `size`.17501751#### `ctypes.memoryview_at(ptr, size, readonly=False)`17521753Возвращает объект [`memoryview`](https://python-all.ru/3.16/library/stdtypes.html#memoryview) длины *size*, который ссылается на память, начинающуюся с *void \*ptr*.17541755Если *readonly* равен true, возвращаемый объект `memoryview` не может использоваться для изменения базовой памяти. (Изменения, сделанные другими способами, всё равно будут отражены в возвращаемом объекте.)17561757Эта функция похожа на [`string_at()`](https://python-all.ru/3.16/library/ctypes.html#ctypes.string_at), с ключевым отличием: не создаётся копия указанной памяти. Это семантически эквивалентная (но более эффективная) альтернатива `memoryview((c_byte * size).from_address(ptr))`. (В то время как [`from_address()`](https://python-all.ru/3.16/library/ctypes.html#ctypes._CData.from_address) принимает только целые числа, *ptr* также может быть задан как объект [`ctypes.POINTER`](https://python-all.ru/3.16/library/ctypes.html#ctypes.POINTER) или [`byref()`](https://python-all.ru/3.16/library/ctypes.html#ctypes.byref).)17581759Вызывает [событие аудита](https://python-all.ru/3.16/library/sys.html#auditing) `ctypes.memoryview_at` с аргументами `address`, `size`, `readonly`.17601761Добавлено в версии 3.14.17621763### Типы данных17641765#### `class ctypes._CData`17661767Этот непубличный класс является общей базой всех типов данных ctypes. Среди прочего, все экземпляры типов ctypes содержат блок памяти, хранящий C-совместимые данные; адрес этого блока возвращается вспомогательной функцией [`addressof()`](https://python-all.ru/3.16/library/ctypes.html#ctypes.addressof). Ещё одна переменная экземпляра доступна как [`_objects`](https://python-all.ru/3.16/library/ctypes.html#ctypes._CData._objects); она содержит другие объекты Python, которые необходимо хранить в живых на случай, если блок памяти содержит указатели.17681769Общие методы типов данных ctypes, все они являются методами класса (если точнее, это методы [метакласса](https://python-all.ru/3.16/glossary.html#term-metaclass)):17701771#### `from_buffer(source[, offset])`17721773Этот метод возвращает экземпляр ctypes, который разделяет буфер объекта *source*. Объект *source* должен поддерживать интерфейс буфера для записи. Необязательный параметр *offset* указывает смещение в буфере источника в байтах; по умолчанию ноль. Если буфер источника недостаточно велик, возникает исключение [`ValueError`](https://python-all.ru/3.16/library/exceptions.html#ValueError).17741775Вызывает [событие аудита](https://python-all.ru/3.16/library/sys.html#auditing) `ctypes.cdata/buffer` с аргументами `pointer`, `size`, `offset`.17761777#### `from_buffer_copy(source[, offset])`17781779Этот метод создаёт экземпляр ctypes, копируя буфер из объекта *source*, который должен быть читаемым. Необязательный параметр *offset* задаёт смещение в буфере источника в байтах; по умолчанию ноль. Если буфер источника недостаточно велик, возникает исключение [`ValueError`](https://python-all.ru/3.16/library/exceptions.html#ValueError).17801781Вызывает [событие аудита](https://python-all.ru/3.16/library/sys.html#auditing) `ctypes.cdata/buffer` с аргументами `pointer`, `size`, `offset`.17821783#### `from_address(address)`17841785Этот метод возвращает экземпляр типа ctypes, использующий память, указанную *address*, который должен быть целым числом.17861787Этот метод и другие методы, которые косвенно его вызывают, порождают [событие аудита](https://python-all.ru/3.16/library/sys.html#auditing) `ctypes.cdata` с аргументом `address`.17881789#### `from_param(obj)`17901791Этот метод адаптирует *obj* к типу ctypes. Он вызывается с фактическим объектом, используемым в вызове внешней функции, если этот тип присутствует в кортеже [`argtypes`](https://python-all.ru/3.16/library/ctypes.html#ctypes._CFuncPtr.argtypes) этой функции; он должен вернуть объект, который можно использовать как параметр вызова функции.17921793Все типы данных ctypes имеют реализацию этого метода класса по умолчанию, которая обычно возвращает *obj*, если он является экземпляром этого типа. Некоторые типы также принимают другие объекты.17941795#### `in_dll(library, name)`17961797Этот метод возвращает экземпляр типа ctypes, экспортируемый общей библиотекой. *name* – это имя символа, экспортирующего данные; *library* – загруженная общая библиотека.17981799Общие переменные класса типов данных ctypes:18001801#### `__pointer_type__`18021803Тип указателя, созданный вызовом [`POINTER()`](https://python-all.ru/3.16/library/ctypes.html#ctypes.POINTER) для соответствующего типа данных ctypes. Если тип указателя ещё не был создан, атрибут отсутствует.18041805Добавлено в версии 3.14.18061807Общие переменные экземпляра типов данных ctypes:18081809#### `_b_base_`18101811Иногда экземпляры данных ctypes не являются владельцами содержащегося в них блока памяти, а разделяют часть блока памяти базового объекта. Атрибут только для чтения [`_b_base_`](https://python-all.ru/3.16/library/ctypes.html#ctypes._CData._b_base_) – это корневой объект ctypes, владеющий блоком памяти.18121813#### `_b_needsfree_`18141815Эта переменная только для чтения равна true, когда экземпляр данных ctypes сам выделил блок памяти, и false в противном случае.18161817#### `_objects`18181819Этот элемент может быть `None` или словарём, содержащим объекты Python, которые необходимо удерживать в памяти, чтобы содержимое блока памяти оставалось валидным. Этот объект предоставляется только для отладки; не изменяйте содержимое этого словаря.18201821### Фундаментальные типы данных18221823#### `class ctypes._SimpleCData`18241825Этот непубличный класс является базовым для всех фундаментальных типов данных ctypes. Он упоминается здесь, потому что содержит общие атрибуты фундаментальных типов данных ctypes. `_SimpleCData` является подклассом [`_CData`](https://python-all.ru/3.16/library/ctypes.html#ctypes._CData), поэтому наследует их методы и атрибуты. Типы данных ctypes, которые не являются указателями и не содержат указателей, теперь можно сериализовать с помощью pickle.18261827Экземпляры имеют один атрибут:18281829#### `value`18301831Этот атрибут содержит фактическое значение экземпляра. Для целочисленных типов и типов указателей это целое число, для символьных типов – объект bytes из одного символа или строка, для символьных указателей – объект Python bytes или строка.18321833При получении атрибута `value` из экземпляра ctypes обычно каждый раз возвращается новый объект. `ctypes` *не* реализует возврат исходного объекта, всегда создаётся новый объект. То же самое верно для всех остальных экземпляров объектов ctypes.18341835Каждый подкласс имеет атрибут класса:18361837#### `_type_`18381839Атрибут класса, содержащий внутренний код типа в виде строки. См. [Фундаментальные типы данных](https://python-all.ru/3.16/library/ctypes.html#ctypes-fundamental-data-types) для сводки.18401841Типы, помеченные \* в сводке, могут быть (или всегда являются) псевдонимами другого подкласса `_SimpleCData`, и не обязательно будут использовать указанный код типа. Например, если на платформе типы C long, long long и time\_t совпадают, то [`c_long`](https://python-all.ru/3.16/library/ctypes.html#ctypes.c_long), [`c_longlong`](https://python-all.ru/3.16/library/ctypes.html#ctypes.c_longlong) и [`c_time_t`](https://python-all.ru/3.16/library/ctypes.html#ctypes.c_time_t) ссылаются на один и тот же класс `c_long`, чей код [`_type_`](https://python-all.ru/3.16/library/ctypes.html#ctypes._SimpleCData._type_) равен `'l'`. Код `'L'` использоваться не будет.18421843> **См. также**1844>1845> Модули [`array`](https://python-all.ru/3.16/library/array.html#module-array) и [struct](https://python-all.ru/3.16/library/struct.html#type-codes), а также сторонние модули, такие как [numpy](https://python-all.ru/3.16/library/ctypes.html), используют похожие, но немного отличающиеся коды типов.18461847Фундаментальные типы данных при возврате в качестве результатов вызова внешней функции или, например, при получении полей структур или элементов массивов прозрачно преобразуются в собственные типы Python. Другими словами, если внешняя функция имеет [`restype`](https://python-all.ru/3.16/library/ctypes.html#ctypes._CFuncPtr.restype) с типом [`c_char_p`](https://python-all.ru/3.16/library/ctypes.html#ctypes.c_char_p), вы всегда получите объект Python bytes, *а не* экземпляр `c_char_p`.18481849Подклассы фундаментальных типов данных *не* наследуют это поведение. Так что если `restype` внешней функции является подклассом [`c_void_p`](https://python-all.ru/3.16/library/ctypes.html#ctypes.c_void_p), вы получите экземпляр этого подкласса в результате вызова функции. Разумеется, вы можете получить значение указателя, обратившись к атрибуту `value`.18501851Вот фундаментальные типы данных ctypes:18521853#### `class ctypes.c_byte`18541855Представляет тип данных C signed char и интерпретирует значение как небольшое целое число. Конструктор принимает необязательный целочисленный инициализатор; проверка переполнения не выполняется.18561857#### `class ctypes.c_char`18581859Представляет тип данных C char и интерпретирует значение как один символ. Конструктор принимает необязательный строковый инициализатор; длина строки должна быть ровно один символ.18601861#### `class ctypes.c_char_p`18621863Представляет тип данных C char\*, когда он указывает на строку, завершающуюся нулевым символом. Для обычного символьного указателя, который может также указывать на двоичные данные, следует использовать `POINTER(c_char)`. Конструктор принимает целочисленный адрес или объект bytes.18641865#### `class ctypes.c_double`18661867Представляет тип данных C double. Конструктор принимает необязательный инициализатор с плавающей запятой.18681869#### `class ctypes.c_longdouble`18701871Представляет тип данных C long double. Конструктор принимает необязательный инициализатор с плавающей запятой. На платформах, где `sizeof(long double) == sizeof(double)`, он является псевдонимом [`c_double`](https://python-all.ru/3.16/library/ctypes.html#ctypes.c_double).18721873#### `class ctypes.c_float`18741875Представляет тип данных C float. Конструктор принимает необязательный инициализатор с плавающей запятой.18761877#### `class ctypes.c_double_complex`18781879Представляет тип данных C double complex, если он доступен. Конструктор принимает необязательный инициализатор [`complex`](https://python-all.ru/3.16/library/functions.html#complex).18801881Добавлено в версии 3.14.18821883#### `class ctypes.c_float_complex`18841885Представляет тип данных C float complex, если он доступен. Конструктор принимает необязательный инициализатор [`complex`](https://python-all.ru/3.16/library/functions.html#complex).18861887Добавлено в версии 3.14.18881889#### `class ctypes.c_longdouble_complex`18901891Представляет тип данных C long double complex, если он доступен. Конструктор принимает необязательный инициализатор [`complex`](https://python-all.ru/3.16/library/functions.html#complex).18921893Добавлено в версии 3.14.18941895#### `class ctypes.c_int`18961897Представляет тип данных C signed int. Конструктор принимает необязательный целочисленный инициализатор; проверка переполнения не выполняется. На платформах, где `sizeof(int) == sizeof(long)`, он является псевдонимом для [`c_long`](https://python-all.ru/3.16/library/ctypes.html#ctypes.c_long).18981899#### `class ctypes.c_int8`19001901Представляет 8-битный тип данных C signed int. Это псевдоним для [`c_byte`](https://python-all.ru/3.16/library/ctypes.html#ctypes.c_byte).19021903#### `class ctypes.c_int16`19041905Представляет 16-битный тип данных C signed int. Обычно это псевдоним для [`c_short`](https://python-all.ru/3.16/library/ctypes.html#ctypes.c_short).19061907#### `class ctypes.c_int32`19081909Представляет 32-битный тип данных C signed int. Обычно это псевдоним для [`c_int`](https://python-all.ru/3.16/library/ctypes.html#ctypes.c_int).19101911#### `class ctypes.c_int64`19121913Представляет 64-битный тип данных C signed int. Обычно это псевдоним для [`c_longlong`](https://python-all.ru/3.16/library/ctypes.html#ctypes.c_longlong).19141915#### `class ctypes.c_long`19161917Представляет тип данных C signed long. Конструктор принимает необязательный целочисленный инициализатор; проверка переполнения не выполняется.19181919#### `class ctypes.c_longlong`19201921Представляет тип данных C signed long long. Конструктор принимает необязательный целочисленный инициализатор; проверка переполнения не выполняется. На платформах, где `sizeof(long long) == sizeof(long)`, он является псевдонимом для [`c_long`](https://python-all.ru/3.16/library/ctypes.html#ctypes.c_long).19221923#### `class ctypes.c_short`19241925Представляет тип данных C signed short. Конструктор принимает необязательный целочисленный инициализатор; проверка переполнения не выполняется.19261927#### `class ctypes.c_size_t`19281929Представляет тип данных C `size_t`. Обычно является псевдонимом для другого беззнакового целочисленного типа.19301931#### `class ctypes.c_ssize_t`19321933Представляет тип данных [`Py_ssize_t`](https://python-all.ru/3.16/c-api/intro.html#c.Py_ssize_t). Это знаковая версия `size_t`; то есть тип POSIX `ssize_t`. Обычно является псевдонимом для другого целочисленного типа.19341935Добавлено в версии 3.2.19361937#### `class ctypes.c_time_t`19381939Представляет тип данных C `time_t`. Обычно является псевдонимом для другого целочисленного типа.19401941Добавлено в версии 3.12.19421943#### `class ctypes.c_ubyte`19441945Представляет тип данных C unsigned char, который интерпретирует значение как малое целое. Конструктор принимает необязательный целочисленный инициализатор; проверка переполнения не выполняется.19461947#### `class ctypes.c_uint`19481949Представляет тип данных C unsigned int. Конструктор принимает необязательный целочисленный инициализатор; проверка переполнения не выполняется. На платформах, где `sizeof(int) == sizeof(long)`, он является псевдонимом для [`c_ulong`](https://python-all.ru/3.16/library/ctypes.html#ctypes.c_ulong).19501951#### `class ctypes.c_uint8`19521953Представляет 8-битный тип данных C unsigned int. Это псевдоним для [`c_ubyte`](https://python-all.ru/3.16/library/ctypes.html#ctypes.c_ubyte).19541955#### `class ctypes.c_uint16`19561957Представляет 16-битный тип данных C unsigned int. Обычно является псевдонимом для [`c_ushort`](https://python-all.ru/3.16/library/ctypes.html#ctypes.c_ushort).19581959#### `class ctypes.c_uint32`19601961Представляет 32-битный тип данных C unsigned int. Обычно является псевдонимом для [`c_uint`](https://python-all.ru/3.16/library/ctypes.html#ctypes.c_uint).19621963#### `class ctypes.c_uint64`19641965Представляет 64-битный тип данных C unsigned int. Обычно является псевдонимом для [`c_ulonglong`](https://python-all.ru/3.16/library/ctypes.html#ctypes.c_ulonglong).19661967#### `class ctypes.c_ulong`19681969Представляет тип данных C unsigned long. Конструктор принимает необязательный целочисленный инициализатор; проверка переполнения не производится.19701971#### `class ctypes.c_ulonglong`19721973Представляет тип данных C unsigned long long. Конструктор принимает необязательный целочисленный инициализатор; проверка переполнения не производится. На платформах, где `sizeof(long long) == sizeof(long)`, это псевдоним для [`c_long`](https://python-all.ru/3.16/library/ctypes.html#ctypes.c_long).19741975#### `class ctypes.c_ushort`19761977Представляет тип данных C unsigned short. Конструктор принимает необязательный целочисленный инициализатор; проверка переполнения не производится.19781979#### `class ctypes.c_void_p`19801981Представляет тип C void\*. Значение представляется как целое число. Конструктор принимает необязательный целочисленный инициализатор.19821983#### `class ctypes.c_wchar`19841985Представляет тип данных C `wchar_t` и интерпретирует значение как строку Unicode из одного символа. Конструктор принимает необязательный строковый инициализатор; длина строки должна быть ровно один символ.19861987#### `class ctypes.c_wchar_p`19881989Представляет тип данных C wchar\_t\*, который должен быть указателем на широкую строку с завершающим нулевым символом. Конструктор принимает целочисленный адрес или строку.19901991#### `class ctypes.c_bool`19921993Представляет тип данных C bool (точнее, \_Bool из C99). Его значением может быть `True` или `False`, а конструктор принимает любой объект, имеющий значение истинности.19941995#### `class ctypes.HRESULT`19961997Представляет значение `HRESULT`, которое содержит информацию об успехе или ошибке для вызова функции или метода.19981999[Доступность](https://python-all.ru/3.16/library/intro.html#availability): Windows20002001#### `class ctypes.py_object`20022003Представляет тип данных C [PyObject](https://python-all.ru/3.16/c-api/structures.html#c.PyObject)\*. Вызов без аргументов создает указатель `NULL` PyObject\*.20042005Изменено в версии 3.14: `py_object` теперь является [обобщённым типом](https://python-all.ru/3.16/glossary.html#term-generic-type).20062007Модуль `ctypes.wintypes` предоставляет довольно много других специфичных для Windows типов данных, например `HWND`, `WPARAM`, `VARIANT_BOOL` или `DWORD`. Также определены некоторые полезные структуры, такие как `MSG` или `RECT`.20082009### Структурированные типы данных20102011#### `class ctypes.Union(*args, **kw)`20122013Абстрактный базовый класс для объединений в собственном порядке байт.20142015Объединения имеют общие атрибуты и поведение со структурами; подробнее см. документацию [`Structure`](https://python-all.ru/3.16/library/ctypes.html#ctypes.Structure).20162017#### `class ctypes.BigEndianUnion(*args, **kw)`20182019Абстрактный базовый класс для объединений в *big endian* порядке байтов.20202021Добавлено в версии 3.12.20222023#### `class ctypes.LittleEndianUnion(*args, **kw)`20242025Абстрактный базовый класс для объединений в *little endian* порядке байтов.20262027Добавлено в версии 3.12.20282029#### `class ctypes.BigEndianStructure(*args, **kw)`20302031Абстрактный базовый класс для структур в *big endian* порядке байтов.20322033#### `class ctypes.LittleEndianStructure(*args, **kw)`20342035Абстрактный базовый класс для структур в *little endian* порядке байтов.20362037Структуры и объединения с не нативным порядком байтов не могут содержать поля-указатели или любые другие типы данных, содержащие поля-указатели.20382039#### `class ctypes.Structure(*args, **kw)`20402041Абстрактный базовый класс для структур в *нативном* порядке байтов.20422043Конкретные типы структур и объединений должны создаваться путем наследования одного из этих типов и как минимум определять переменную класса [`_fields_`](https://python-all.ru/3.16/library/ctypes.html#ctypes.Structure._fields_). `ctypes` создаст [дескриптор](https://python-all.ru/3.16/glossary.html#term-descriptor)ы, которые позволяют читать и записывать поля через прямой доступ к атрибутам. Это –20442045#### `_fields_`20462047Последовательность, определяющая поля структуры. Элементы должны быть 2-кортежами или 3-кортежами. Первый элемент – имя поля, второй элемент задает тип поля; это может быть любой тип данных ctypes.20482049Для полей целочисленного типа, таких как [`c_int`](https://python-all.ru/3.16/library/ctypes.html#ctypes.c_int), можно указать третий необязательный элемент. Он должен быть небольшим положительным целым числом, определяющим разрядность поля (битовую ширину).20502051Имена полей должны быть уникальными в пределах одной структуры или объединения. Это не проверяется, но при повторении имен доступно только одно поле.20522053Можно определить переменную класса [`_fields_`](https://python-all.ru/3.16/library/ctypes.html#ctypes.Structure._fields_) *после* оператора class, определяющего подкласс Structure; это позволяет создавать типы данных, которые прямо или косвенно ссылаются сами на себя:20542055```python2056class List(Structure):2057    pass2058List._fields_ = [("pnext", POINTER(List)),2059                 ...2060                ]2061```20622063Переменную класса `_fields_` можно установить только один раз. Последующие присваивания вызовут исключение [`AttributeError`](https://python-all.ru/3.16/library/exceptions.html#AttributeError).20642065Кроме того, переменная класса `_fields_` должна быть определена до первого использования типа структуры или объединения: создается экземпляр или подкласс, вызывается [`sizeof()`](https://python-all.ru/3.16/library/ctypes.html#ctypes.sizeof) и т.д. Последующие присваивания `_fields_` вызовут исключение [`AttributeError`](https://python-all.ru/3.16/library/exceptions.html#AttributeError). Если `_fields_` не была установлена до такого использования, структура или объединение не будет иметь собственных полей, как если бы `_fields_` была пуста.20662067Подподклассы типов структур наследуют поля базового класса плюс [`_fields_`](https://python-all.ru/3.16/library/ctypes.html#ctypes.Structure._fields_), определенный в подподклассе, если таковой имеется.20682069#### `_pack_`20702071Необязательное небольшое целое число, которое позволяет переопределить выравнивание полей структуры в экземпляре.20722073Это реализовано только для совместимой с MSVC компоновки памяти (см. [`_layout_`](https://python-all.ru/3.16/library/ctypes.html#ctypes.Structure._layout_)).20742075Установка `_pack_` в 0 равносильна его отсутствию. В противном случае значение должно быть положительной степенью двойки. Эффект эквивалентен `#pragma pack(N)` в C, за исключением того, что `ctypes` может допускать большие значения *n*, чем принимает компилятор.20762077`_pack_` должен быть уже определен на момент присваивания [`_fields_`](https://python-all.ru/3.16/library/ctypes.html#ctypes.Structure._fields_), иначе это не будет иметь эффекта.20782079Устарело с версии 3.14, будет удалено в версии 3.19: По историческим причинам, если `_pack_` не равно нулю, по умолчанию используется совместимая с MSVC компоновка памяти. На платформах, отличных от Windows, это поведение по умолчанию устарело и должно стать ошибкой в Python 3.19. Если это предполагается, явно установите [`_layout_`](https://python-all.ru/3.16/library/ctypes.html#ctypes.Structure._layout_) в `'ms'`.20802081#### `_align_`20822083Необязательное небольшое целое число, которое позволяет увеличить выравнивание структуры при упаковке или распаковке в/из памяти.20842085Значение не должно быть отрицательным. Эффект эквивалентен `__attribute__((aligned(N)))` в GCC или `#pragma align(N)` в MSVC, за исключением того, что `ctypes` может допускать значения, которые компилятор отверг бы.20862087`_align_` может только *увеличить* требования к выравниванию структуры. Установка его в 0 или 1 не имеет эффекта.20882089Использование значений, не являющихся степенями двойки, не рекомендуется и может привести к неожиданному поведению.20902091`_align_` должен быть уже определен на момент присваивания [`_fields_`](https://python-all.ru/3.16/library/ctypes.html#ctypes.Structure._fields_), иначе это не будет иметь эффекта.20922093Добавлено в версии 3.13.20942095#### `_layout_`20962097Необязательная строка, задающая макет структуры или объединения. В настоящее время может принимать следующие значения:20982099- `"ms"`: макет, используемый компилятором Microsoft (MSVC). На GCC и Clang этот макет можно выбрать с помощью `__attribute__((ms_struct))`.2100- `"gcc-sysv"`: макет, используемый GCC с моделью данных System V или «SysV-подобной», применяемой в Linux и macOS. При этом макете [`_pack_`](https://python-all.ru/3.16/library/ctypes.html#ctypes.Structure._pack_) должен быть не задан или равен нулю.21012102Если не задано явно, `ctypes` будет использовать значение по умолчанию, соответствующее соглашениям платформы. Это значение по умолчанию может измениться в будущих выпусках Python (например, при официальной поддержке новой платформы или обнаружении различий между похожими платформами). В настоящее время значением по умолчанию является:21032104- В Windows: `"ms"`2105- Если указан [`_pack_`](https://python-all.ru/3.16/library/ctypes.html#ctypes.Structure._pack_): `"ms"`. (Устарело; см. документацию `_pack_`.)2106- В противном случае: `"gcc-sysv"`21072108`_layout_` должен быть уже определён, когда присваивается [`_fields_`](https://python-all.ru/3.16/library/ctypes.html#ctypes.Structure._fields_), иначе это не будет иметь эффекта.21092110Добавлено в версии 3.14.21112112#### `_anonymous_`21132114Необязательная последовательность, перечисляющая имена безымянных (анонимных) полей. [`_anonymous_`](https://python-all.ru/3.16/library/ctypes.html#ctypes.Structure._anonymous_) должен быть уже определён, когда присваивается [`_fields_`](https://python-all.ru/3.16/library/ctypes.html#ctypes.Structure._fields_), иначе это не будет иметь эффекта.21152116Поля, перечисленные в этой переменной, должны быть полями структурного или объединённого типа. `ctypes` создаёт дескрипторы в типе структуры, которые позволяют напрямую обращаться к вложенным полям без необходимости создания поля структуры или объединения.21172118Вот пример типа (Windows):21192120```python2121class _U(Union):2122    _fields_ = [("lptdesc", POINTER(TYPEDESC)),2123                ("lpadesc", POINTER(ARRAYDESC)),2124                ("hreftype", HREFTYPE)]21252126class TYPEDESC(Structure):2127    _anonymous_ = ("u",)2128    _fields_ = [("u", _U),2129                ("vt", VARTYPE)]2130```21312132Структура `TYPEDESC` описывает COM-тип данных, поле `vt` указывает, какое из полей объединения является действительным. Поскольку поле `u` определено как анонимное, теперь можно обращаться к членам напрямую через экземпляр TYPEDESC. `td.lptdesc` и `td.u.lptdesc` эквивалентны, но первый вариант быстрее, так как не требует создания временного экземпляра объединения:21332134```python2135td = TYPEDESC()2136td.vt = VT_PTR2137td.lptdesc = POINTER(some_type)2138td.u.lptdesc = POINTER(some_type)2139```21402141Можно определять подклассы структур; они наследуют поля базового класса. Если в определении подкласса есть отдельная переменная [`_fields_`](https://python-all.ru/3.16/library/ctypes.html#ctypes.Structure._fields_), поля, указанные в ней, добавляются к полям базового класса.21422143Конструкторы структур и объединений принимают как позиционные, так и именованные аргументы. Позиционные аргументы используются для инициализации полей-членов в том же порядке, в котором они перечислены в [`_fields_`](https://python-all.ru/3.16/library/ctypes.html#ctypes.Structure._fields_). Именованные аргументы в конструкторе интерпретируются как присваивания атрибутов, поэтому они инициализируют `_fields_` с тем же именем или создают новые атрибуты для имён, отсутствующих в `_fields_`.21442145#### `class ctypes.CField(*args, **kw)`21462147Дескриптор для полей [`Structure`](https://python-all.ru/3.16/library/ctypes.html#ctypes.Structure) и [`Union`](https://python-all.ru/3.16/library/ctypes.html#ctypes.Union). Например:21482149```python2150>>> class Color(Structure):2151...     _fields_ = (2152...         ('red', c_uint8),2153...         ('green', c_uint8),2154...         ('blue', c_uint8),2155...         ('intense', c_bool, 1),2156...         ('blinking', c_bool, 1),2157...    )2158...2159>>> Color.red2160<ctypes.CField 'red' type=c_ubyte, ofs=0, size=1>2161>>> Color.green.type2162<class 'ctypes.c_ubyte'>2163>>> Color.blue.byte_offset216422165>>> Color.intense2166<ctypes.CField 'intense' type=c_bool, ofs=3, bit_size=1, bit_offset=0>2167>>> Color.blinking.bit_offset216812169```21702171Все атрибуты доступны только для чтения.21722173Объекты `CField` создаются через [`_fields_`](https://python-all.ru/3.16/library/ctypes.html#ctypes.Structure._fields_); не создавайте экземпляр класса напрямую.21742175Добавлено в версии 3.14: Ранее дескрипторы имели только атрибуты `offset` и `size` и читаемое строковое представление; класс `CField` не был доступен напрямую.21762177#### `name`21782179Имя поля в виде строки.21802181#### `type`21822183Тип поля в виде [класс ctypes](https://python-all.ru/3.16/library/ctypes.html#ctypes-data-types).21842185#### `offset`21862187#### `byte_offset`21882189Смещение поля в байтах.21902191Для битовых полей это смещение нижележащей *единицы хранения, выровненной по байтам*; см. [`bit_offset`](https://python-all.ru/3.16/library/ctypes.html#ctypes.CField.bit_offset).21922193#### `byte_size`21942195Размер поля в байтах.21962197Для битовых полей это размер нижележащей *единицы хранения*. Обычно он совпадает с размером типа битового поля.21982199#### `size`22002201Для небитовых полей эквивалентно [`byte_size`](https://python-all.ru/3.16/library/ctypes.html#ctypes.CField.byte_size).22022203Для битовых полей это содержит обратно совместимое упакованное битовое значение, которое объединяет [`bit_size`](https://python-all.ru/3.16/library/ctypes.html#ctypes.CField.bit_size) и [`bit_offset`](https://python-all.ru/3.16/library/ctypes.html#ctypes.CField.bit_offset). Вместо этого рекомендуется использовать явные атрибуты.22042205#### `is_bitfield`22062207True, если это битовое поле.22082209#### `bit_offset`22102211#### `bit_size`22122213Расположение битового поля внутри его *единицы хранения*, то есть в пределах [`byte_size`](https://python-all.ru/3.16/library/ctypes.html#ctypes.CField.byte_size) байтов памяти, начиная с [`byte_offset`](https://python-all.ru/3.16/library/ctypes.html#ctypes.CField.byte_offset).22142215Чтобы получить значение поля, прочитайте единицу хранения как целое число, [сдвиньте влево](https://python-all.ru/3.16/reference/expressions.html#shifting) на `bit_offset` и возьмите `bit_size` младших битов.22162217Для небитовых полей `bit_offset` равно нулю, а `bit_size` равно `byte_size * 8`.22182219#### `is_anonymous`22202221True, если это поле анонимное, то есть содержит вложенные подполя, которые должны быть объединены в содержащую структуру или объединение.22222223### Массивы и указатели22242225#### `class ctypes.Array(*args)`22262227Абстрактный базовый класс для массивов.22282229Рекомендуемый способ создания конкретных типов массивов – умножение любого `ctypes` типа данных на неотрицательное целое число. В качестве альтернативы можно создать подкласс этого типа и определить переменные класса [`_length_`](https://python-all.ru/3.16/library/ctypes.html#ctypes.Array._length_) и [`_type_`](https://python-all.ru/3.16/library/ctypes.html#ctypes.Array._type_). Элементы массива можно читать и записывать с помощью стандартных операций индексирования и срезов; при чтении среза результирующий объект *не* является `Array`.22302231Массивы являются [обобщёнными](https://python-all.ru/3.16/library/typing.html#generics) по типу своих элементов.22322233#### `_length_`22342235Положительное целое число, задающее количество элементов в массиве. Индексы вне диапазона приводят к [`IndexError`](https://python-all.ru/3.16/library/exceptions.html#IndexError). Будет возвращено [`len()`](https://python-all.ru/3.16/library/functions.html#len).22362237#### `_type_`22382239Задаёт тип каждого элемента в массиве.22402241Конструкторы подклассов массивов принимают позиционные аргументы, используемые для инициализации элементов по порядку.22422243#### `ctypes.ARRAY(type, length)`22442245Создание массива. Эквивалентно `type * length`, где *type* – это `ctypes` тип данных, а *length* – целое число.22462247[Мягко устарело](https://python-all.ru/3.16/glossary.html#term-soft-deprecated) с версии 3.14: В пользу умножения.22482249#### `class ctypes._Pointer`22502251Приватный абстрактный базовый класс для указателей.22522253Конкретные типы указателей создаются вызовом [`POINTER()`](https://python-all.ru/3.16/library/ctypes.html#ctypes.POINTER) с типом, на который будет указываться; это делается автоматически [`pointer()`](https://python-all.ru/3.16/library/ctypes.html#ctypes.pointer).22542255Если указатель указывает на массив, его элементы можно читать и записывать с помощью стандартных операций индексирования и срезов. Объекты-указатели не имеют размера, поэтому [`len()`](https://python-all.ru/3.16/library/functions.html#len) вызовет [`TypeError`](https://python-all.ru/3.16/library/exceptions.html#TypeError). Отрицательные индексы будут читать из памяти *до* указателя (как в C), а индексы за пределами диапазона, скорее всего, приведут к сбою с нарушением доступа (если повезёт).22562257#### `_type_`22582259Задаёт тип, на который указывается.22602261#### `contents`22622263Возвращает объект, на который указывает указатель. Присваивание этому атрибуту изменяет указатель так, чтобы он указывал на присвоенный объект.22642265### Исключения22662267#### `exception ctypes.ArgumentError`22682269Это исключение возникает, когда вызов внешней функции не может преобразовать один из переданных аргументов.22702271#### `exception ctypes.COMError(hresult, text, details)`22722273Это исключение возникает, когда вызов COM-метода завершился ошибкой.22742275#### `hresult`22762277Целочисленное значение, представляющее код ошибки.22782279#### `text`22802281Сообщение об ошибке.22822283#### `details`228422855-кортеж `(descr, source, helpfile, helpcontext, progid)`.22862287*descr* – текстовое описание. *source* – языкозависимый `ProgID` для класса или приложения, вызвавшего ошибку. *helpfile* – путь к файлу справки. *helpcontext* – идентификатор контекста справки. *progid*`ProgID` интерфейса, определившего ошибку.22882289[Доступность](https://python-all.ru/3.16/library/intro.html#availability): Windows22902291Добавлено в версии 3.14.2292