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

ctypes.md

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

1> **Источник:** https://python-all.ru/2.7/library/ctypes.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# 15.17. [`ctypes`](https://python-all.ru/2.7/library/ctypes.html#module-ctypes) – Библиотека внешних функций для Python89Новое в версии 2.5.1011[`ctypes`](https://python-all.ru/2.7/library/ctypes.html#module-ctypes) – это библиотека для вызова внешних функций на Python. Она предоставляет совместимые с C типы данных и позволяет вызывать функции из DLL или разделяемых библиотек. Её можно использовать для обёртывания этих библиотек на чистом Python.1213## 15.17.1. Руководство по ctypes1415Примечание: примеры кода в этом руководстве используют [`doctest`](https://python-all.ru/2.7/library/doctest.html#module-doctest), чтобы убедиться, что они действительно работают. Поскольку некоторые примеры ведут себя по-разному в Linux, Windows или Mac OS X, в комментариях они содержат директивы doctest.1617Примечание. Некоторые примеры кода ссылаются на тип [`c_int`](https://python-all.ru/2.7/library/ctypes.html#ctypes.c_int) модуля ctypes. Этот тип является псевдонимом для типа [`c_long`](https://python-all.ru/2.7/library/ctypes.html#ctypes.c_long) в 32-битных системах. Поэтому не стоит удивляться, если выводится [`c_long`](https://python-all.ru/2.7/library/ctypes.html#ctypes.c_long), когда ожидается [`c_int`](https://python-all.ru/2.7/library/ctypes.html#ctypes.c_int) – на самом деле это один и тот же тип.1819### 15.17.1.1. Загрузка динамически подключаемых библиотек2021[`ctypes`](https://python-all.ru/2.7/library/ctypes.html#module-ctypes) экспортирует объекты *cdll*, а в Windows – *windll* и *oledll* для загрузки динамически подключаемых библиотек.2223Библиотеки загружаются обращением к ним как к атрибутам этих объектов. *cdll* загружает библиотеки, экспортирующие функции со стандартным соглашением о вызовах `cdecl`, в то время как библиотеки *windll* вызывают функции, используя соглашение `stdcall`. *oledll* также использует соглашение `stdcall` и предполагает, что функции возвращают код ошибки Windows `HRESULT`. Этот код ошибки используется для автоматического возбуждения исключения `WindowsError` при неудачном вызове функции.2425Вот несколько примеров для Windows. Обратите внимание, что `msvcrt` – это стандартная библиотека C от Microsoft, содержащая большинство стандартных функций C, и использует соглашение о вызовах cdecl:2627```python28>>> from ctypes import *29>>> print windll.kernel32  30<WinDLL 'kernel32', handle ... at ...>31>>> print cdll.msvcrt      32<CDLL 'msvcrt', handle ... at ...>33>>> libc = cdll.msvcrt     34>>>35```3637Windows автоматически добавляет обычный суффикс файла `.dll`.3839В Linux необходимо указывать имя файла *вместе с расширением* для загрузки библиотеки, поэтому для загрузки библиотек нельзя использовать обращение к атрибутам. Следует использовать метод `LoadLibrary()` загрузчиков dll или загрузить библиотеку, создав экземпляр CDLL через вызов конструктора:4041```python42>>> cdll.LoadLibrary("libc.so.6")  43<CDLL 'libc.so.6', handle ... at ...>44>>> libc = CDLL("libc.so.6")       45>>> libc                           46<CDLL 'libc.so.6', handle ... at ...>47>>>48```4950### 15.17.1.2. Доступ к функциям из загруженных DLL5152Функции доступны как атрибуты объектов DLL:5354```python55>>> from ctypes import *56>>> libc.printf57<_FuncPtr object at 0x...>58>>> print windll.kernel32.GetModuleHandleA  59<_FuncPtr object at 0x...>60>>> print windll.kernel32.MyOwnFunction     61Traceback (most recent call last):62  File "<stdin>", line 1, in <module>63  File "ctypes.py", line 239, in __getattr__64    func = _StdcallFuncPtr(name, self)65AttributeError: function 'MyOwnFunction' not found66>>>67```6869Обратите внимание, что системные библиотеки win32, такие как `kernel32` и `user32`, часто экспортируют как ANSI, так и UNICODE версии функции. Версия UNICODE экспортируется с `W` в конце имени, а версия ANSI – с `A`. Функция win32 `GetModuleHandle`, которая возвращает *дескриптор модуля* для заданного имени модуля, имеет следующий прототип на C, и макрос используется, чтобы предоставить одну из них как `GetModuleHandle` в зависимости от того, определён ли UNICODE:7071```python72/* ANSI version */73HMODULE GetModuleHandleA(LPCSTR lpModuleName);74/* UNICODE version */75HMODULE GetModuleHandleW(LPCWSTR lpModuleName);76```7778*windll* не пытается выбрать одну из них магическим образом – нужную версию необходимо получить, указав `GetModuleHandleA` или `GetModuleHandleW` явно, а затем вызывать её со строками или строками Юникода соответственно.7980Иногда DLL экспортируют функции с именами, которые не являются допустимыми идентификаторами Python, например `"??2@YAPAXI@Z"`. В этом случае нужно использовать [`getattr()`](https://python-all.ru/2.7/library/functions.html#getattr) для получения функции:8182```python83>>> getattr(cdll.msvcrt, "??2@YAPAXI@Z")  84<_FuncPtr object at 0x...>85>>>86```8788В Windows некоторые DLL экспортируют функции не по имени, а по порядковому номеру. К таким функциям можно получить доступ, индексируя объект DLL по порядковому номеру:8990```python91>>> cdll.kernel32[1]  92<_FuncPtr object at 0x...>93>>> cdll.kernel32[0]  94Traceback (most recent call last):95  File "<stdin>", line 1, in <module>96  File "ctypes.py", line 310, in __getitem__97    func = _StdcallFuncPtr(name, self)98AttributeError: function ordinal 0 not found99>>>100```101102### 15.17.1.3. Вызов функций103104Эти функции можно вызывать как любой другой вызываемый объект Python. В этом примере используется функция `time()`, которая возвращает системное время в секундах, прошедших с начала эпохи Unix, и функция `GetModuleHandleA()`, которая возвращает дескриптор модуля win32.105106В этом примере обе функции вызываются с нулевым указателем (`None` следует использовать в качестве нулевого указателя):107108```python109>>> print libc.time(None)  1101150640792111>>> print hex(windll.kernel32.GetModuleHandleA(None))  1120x1d000000113>>>114```115116[`ctypes`](https://python-all.ru/2.7/library/ctypes.html#module-ctypes) пытается защитить вас от вызова функций с неверным числом аргументов или неверным соглашением о вызове. К сожалению, это работает только в Windows. Он проверяет стек после возврата функции, поэтому хотя и генерируется исключение, функция *была* вызвана:117118```python119>>> windll.kernel32.GetModuleHandleA()      120Traceback (most recent call last):121  File "<stdin>", line 1, in <module>122ValueError: Procedure probably called with not enough arguments (4 bytes missing)123>>> windll.kernel32.GetModuleHandleA(0, 0)  124Traceback (most recent call last):125  File "<stdin>", line 1, in <module>126ValueError: Procedure probably called with too many arguments (4 bytes in excess)127>>>128```129130То же исключение возникает при вызове функции `stdcall` с соглашением о вызове `cdecl` и наоборот:131132```python133>>> cdll.kernel32.GetModuleHandleA(None)  134Traceback (most recent call last):135  File "<stdin>", line 1, in <module>136ValueError: Procedure probably called with not enough arguments (4 bytes missing)137>>>138139>>> windll.msvcrt.printf("spam")  140Traceback (most recent call last):141  File "<stdin>", line 1, in <module>142ValueError: Procedure probably called with too many arguments (4 bytes in excess)143>>>144```145146Чтобы узнать правильное соглашение о вызовах, необходимо заглянуть в C-заголовочный файл или документацию вызываемой функции.147148В Windows [`ctypes`](https://python-all.ru/2.7/library/ctypes.html#module-ctypes) использует структурированную обработку исключений win32 для предотвращения сбоев из-за ошибок общей защиты при вызове функций с недопустимыми значениями аргументов:149150```python151>>> windll.kernel32.GetModuleHandleA(32)  152Traceback (most recent call last):153  File "<stdin>", line 1, in <module>154WindowsError: exception: access violation reading 0x00000020155>>>156```157158Тем не менее, существует достаточно способов «уронить» Python с помощью [`ctypes`](https://python-all.ru/2.7/library/ctypes.html#module-ctypes), так что в любом случае стоит быть осторожным.159160`None`, целые числа, длинные целые, байтовые строки и строки Юникода – единственные встроенные объекты Python, которые можно напрямую использовать в качестве параметров в этих вызовах функций. `None` передаётся как указатель C `NULL`, байтовые строки и строки Юникода передаются как указатель на блок памяти, содержащий их данные (`char *` или `wchar_t *`). Целые числа Python и длинные целые Python передаются как принятый на платформе по умолчанию тип C `int`, их значение маскируется, чтобы поместиться в тип C.161162Прежде чем перейти к вызову функций с другими типами параметров, нужно узнать больше о типах данных [`ctypes`](https://python-all.ru/2.7/library/ctypes.html#module-ctypes).163164### 15.17.1.4. Фундаментальные типы данных165166[`ctypes`](https://python-all.ru/2.7/library/ctypes.html#module-ctypes) определяет несколько примитивных типов данных, совместимых с C:167168| Тип ctypes | Тип C | Тип Python |169| --- | --- | --- |170| [`c_bool`](https://python-all.ru/2.7/library/ctypes.html#ctypes.c_bool) | `_Bool` | bool (1) |171| [`c_char`](https://python-all.ru/2.7/library/ctypes.html#ctypes.c_char) | `char` | односимвольная строка |172| [`c_wchar`](https://python-all.ru/2.7/library/ctypes.html#ctypes.c_wchar) | `wchar_t` | строка Unicode из одного символа |173| [`c_byte`](https://python-all.ru/2.7/library/ctypes.html#ctypes.c_byte) | `char` | int/long |174| [`c_ubyte`](https://python-all.ru/2.7/library/ctypes.html#ctypes.c_ubyte) | `unsigned char` | int/long |175| [`c_short`](https://python-all.ru/2.7/library/ctypes.html#ctypes.c_short) | `short` | int/long |176| [`c_ushort`](https://python-all.ru/2.7/library/ctypes.html#ctypes.c_ushort) | `unsigned short` | int/long |177| [`c_int`](https://python-all.ru/2.7/library/ctypes.html#ctypes.c_int) | `int` | int/long |178| [`c_uint`](https://python-all.ru/2.7/library/ctypes.html#ctypes.c_uint) | `unsigned int` | int/long |179| [`c_long`](https://python-all.ru/2.7/library/ctypes.html#ctypes.c_long) | `long` | int/long |180| [`c_ulong`](https://python-all.ru/2.7/library/ctypes.html#ctypes.c_ulong) | `unsigned long` | int/long |181| [`c_longlong`](https://python-all.ru/2.7/library/ctypes.html#ctypes.c_longlong) | `__int64` или `long long` | int/long |182| [`c_ulonglong`](https://python-all.ru/2.7/library/ctypes.html#ctypes.c_ulonglong) | `unsigned __int64` или `unsigned long long` | int/long |183| [`c_float`](https://python-all.ru/2.7/library/ctypes.html#ctypes.c_float) | `float` | float |184| [`c_double`](https://python-all.ru/2.7/library/ctypes.html#ctypes.c_double) | `double` | float |185| [`c_longdouble`](https://python-all.ru/2.7/library/ctypes.html#ctypes.c_longdouble) | `long double` | float |186| [`c_char_p`](https://python-all.ru/2.7/library/ctypes.html#ctypes.c_char_p) | `char *` (с завершающим нулём) | строка или `None` |187| [`c_wchar_p`](https://python-all.ru/2.7/library/ctypes.html#ctypes.c_wchar_p) | `wchar_t *` (с завершающим нулём) | unicode или `None` |188| [`c_void_p`](https://python-all.ru/2.7/library/ctypes.html#ctypes.c_void_p) | `void *` | int/long или `None` |1891901. Конструктор принимает любой объект с истинностным значением.191192Все эти типы можно создать, вызвав их с необязательным инициализатором правильного типа и значения:193194```python195>>> c_int()196c_long(0)197>>> c_char_p("Hello, World")198c_char_p('Hello, World')199>>> c_ushort(-3)200c_ushort(65533)201>>>202```203204Поскольку эти типы изменяемы, их значение можно изменить и впоследствии:205206```python207>>> i = c_int(42)208>>> print i209c_long(42)210>>> print i.value21142212>>> i.value = -99213>>> print i.value214-99215>>>216```217218Присвоение нового значения экземплярам типов-указателей [`c_char_p`](https://python-all.ru/2.7/library/ctypes.html#ctypes.c_char_p), [`c_wchar_p`](https://python-all.ru/2.7/library/ctypes.html#ctypes.c_wchar_p) и [`c_void_p`](https://python-all.ru/2.7/library/ctypes.html#ctypes.c_void_p) изменяет *адрес памяти*, на который они указывают, *а не содержимое* блока памяти (конечно, нет, потому что строки Python неизменяемы):219220```python221>>> s = "Hello, World"222>>> c_s = c_char_p(s)223>>> print c_s224c_char_p('Hello, World')225>>> c_s.value = "Hi, there"226>>> print c_s227c_char_p('Hi, there')228>>> print s                 # первая строка не изменяется229Hello, World230>>>231```232233Однако следует соблюдать осторожность: не передавайте их функциям, ожидающим указатели на изменяемую память. Если нужны изменяемые блоки памяти, в ctypes есть функция [`create_string_buffer()`](https://python-all.ru/2.7/library/ctypes.html#ctypes.create_string_buffer), которая создаёт их разными способами. Текущее содержимое блока памяти можно получить (или изменить) через свойство `raw`; если нужно обратиться к нему как к строке, завершающейся NUL, используйте свойство `value`:234235```python236>>> from ctypes import *237>>> p = create_string_buffer(3)      # создать буфер размером 3 байта, инициализированный нулевыми байтами238>>> print sizeof(p), repr(p.raw)2393 '\x00\x00\x00'240>>> p = create_string_buffer("Hello")      # создать буфер, содержащий строку, завершающуюся нулевым байтом241>>> print sizeof(p), repr(p.raw)2426 'Hello\x00'243>>> print repr(p.value)244'Hello'245>>> p = create_string_buffer("Hello", 10)  # создать буфер на 10 байт246>>> print sizeof(p), repr(p.raw)24710 'Hello\x00\x00\x00\x00\x00'248>>> p.value = "Hi"249>>> print sizeof(p), repr(p.raw)25010 'Hi\x00lo\x00\x00\x00\x00\x00'251>>>252```253254Функция [`create_string_buffer()`](https://python-all.ru/2.7/library/ctypes.html#ctypes.create_string_buffer) заменяет функцию `c_buffer()` (которая всё ещё доступна как псевдоним), а также функцию `c_string()` из более ранних версий ctypes. Чтобы создать изменяемый блок памяти, содержащий символы Unicode типа C `wchar_t`, используйте функцию [`create_unicode_buffer()`](https://python-all.ru/2.7/library/ctypes.html#ctypes.create_unicode_buffer).255256### 15.17.1.5. Вызов функций, продолжение257258Обратите внимание: printf выводит в реальный стандартный поток вывода, *а не* в [`sys.stdout`](https://python-all.ru/2.7/library/sys.html#sys.stdout), поэтому эти примеры будут работать только в консоли, а не из *IDLE* или *PythonWin*:259260```python261>>> printf = libc.printf262>>> printf("Hello, %s\n", "World!")263Hello, World!26414265>>> printf("Hello, %S\n", u"World!")266Hello, World!26714268>>> printf("%d bottles of beer\n", 42)26942 bottles of beer27019271>>> printf("%f bottles of beer\n", 42.5)272Traceback (most recent call last):273  File "<stdin>", line 1, in <module>274ArgumentError: argument 2: exceptions.TypeError: Don't know how to convert parameter 2275>>>276```277278Как уже упоминалось, все типы Python, кроме целых чисел, строк и строк Юникода, должны быть обёрнуты в соответствующий тип [`ctypes`](https://python-all.ru/2.7/library/ctypes.html#module-ctypes), чтобы их можно было преобразовать в требуемый тип C:279280```python281>>> printf("An int %d, a double %f\n", 1234, c_double(3.14))282An int 1234, a double 3.14000028331284>>>285```286287### 15.17.1.6. Вызов функций с собственными пользовательскими типами данных288289Можно также настроить преобразование аргументов [`ctypes`](https://python-all.ru/2.7/library/ctypes.html#module-ctypes), чтобы экземпляры собственных классов можно было использовать в качестве аргументов функций. [`ctypes`](https://python-all.ru/2.7/library/ctypes.html#module-ctypes) ищет атрибут `_as_parameter_` и использует его как аргумент функции. Разумеется, это должно быть целое число, строка или строка Юникода:290291```python292>>> class Bottles(object):293...     def __init__(self, number):294...         self._as_parameter_ = number295...296>>> bottles = Bottles(42)297>>> printf("%d bottles of beer\n", bottles)29842 bottles of beer29919300>>>301```302303Если не требуется хранить данные экземпляра в переменной экземпляра `_as_parameter_`, можно определить [`property()`](https://python-all.ru/2.7/library/functions.html#property), обеспечивающий доступ к данным.304305### 15.17.1.7. Указание необходимых типов аргументов (прототипы функций)306307Можно указать требуемые типы аргументов функций, экспортируемых из DLL, задав атрибут `argtypes`.308309`argtypes` должен быть последовательностью типов данных C (функция `printf` вероятно, не лучший пример, поскольку она принимает переменное количество и разные типы параметров в зависимости от строки формата; с другой стороны, это довольно удобно для экспериментов с этой возможностью):310311```python312>>> printf.argtypes = [c_char_p, c_char_p, c_int, c_double]313>>> printf("String '%s', Int %d, Double %f\n", "Hi", 10, 2.2)314String 'Hi', Int 10, Double 2.20000031537316>>>317```318319Указание формата защищает от несовместимых типов аргументов (как прототип для функции C) и пытается преобразовать аргументы в допустимые типы:320321```python322>>> printf("%d %d %d", 1, 2, 3)323Traceback (most recent call last):324  File "<stdin>", line 1, in <module>325ArgumentError: argument 2: exceptions.TypeError: wrong type326>>> printf("%s %d %f\n", "X", 2, 3)327X 2 3.00000032813329>>>330```331332Если определены собственные классы, которые передаются в вызовы функций, необходимо реализовать метод класса `from_param()`, чтобы иметь возможность использовать их в последовательности `argtypes`. Метод класса `from_param()` получает объект Python, переданный в вызов функции; он должен выполнить проверку типа или всё необходимое, чтобы убедиться, что объект приемлем, а затем вернуть сам объект, его атрибут `_as_parameter_` или то, что требуется передать в качестве аргумента функции C в данном случае. Результат должен быть целым числом, строкой, строкой Юникода, экземпляром [`ctypes`](https://python-all.ru/2.7/library/ctypes.html#module-ctypes) или объектом с атрибутом `_as_parameter_`.333334### 15.17.1.8. Типы возвращаемых значений335336По умолчанию считается, что функции возвращают тип C `int`. Другие возвращаемые типы можно указать, задав атрибут `restype` объекта функции.337338Вот более сложный пример: используется функция `strchr`, которая ожидает указатель на строку и char, а возвращает указатель на строку:339340```python341>>> strchr = libc.strchr342>>> strchr("abcdef", ord("d"))  3438059983344>>> strchr.restype = c_char_p   # c_char_p – указатель на строку345>>> strchr("abcdef", ord("d"))346'def'347>>> print strchr("abcdef", ord("x"))348None349>>>350```351352Чтобы избежать приведённых выше вызовов `ord("x")`, можно установить атрибут `argtypes`, и второй аргумент будет преобразован из односимвольной строки Python в char C:353354```python355>>> strchr.restype = c_char_p356>>> strchr.argtypes = [c_char_p, c_char]357>>> strchr("abcdef", "d")358'def'359>>> strchr("abcdef", "def")360Traceback (most recent call last):361  File "<stdin>", line 1, in <module>362ArgumentError: argument 2: exceptions.TypeError: one character string expected363>>> print strchr("abcdef", "x")364None365>>> strchr("abcdef", "d")366'def'367>>>368```369370В качестве атрибута `restype` можно также использовать вызываемый объект Python (например, функцию или класс), если внешняя функция возвращает целое число. Этот вызываемый объект будет вызван с *целым числом*, которое вернула функция C, и результат этого вызова будет использован как результат вашего вызова функции. Это полезно для проверки кодов ошибок и автоматического возбуждения исключения:371372```python373>>> GetModuleHandle = windll.kernel32.GetModuleHandleA  374>>> def ValidHandle(value):375...     if value == 0:376...         raise WinError()377...     return value378...379>>>380>>> GetModuleHandle.restype = ValidHandle  381>>> GetModuleHandle(None)  382486539264383>>> GetModuleHandle("something silly")  384Traceback (most recent call last):385  File "<stdin>", line 1, in <module>386  File "<stdin>", line 3, in ValidHandle387WindowsError: [Errno 126] The specified module could not be found.388>>>389```390391`WinError` – это функция, которая вызывает Windows API `FormatMessage()` для получения строкового представления кода ошибки и *возвращает* исключение. `WinError` принимает необязательный параметр – код ошибки; если он не указан, функция вызывает [`GetLastError()`](https://python-all.ru/2.7/library/ctypes.html#ctypes.GetLastError) для его получения.392393Обратите внимание, что гораздо более мощный механизм проверки ошибок доступен\\nчерез атрибут `errcheck`; подробнее см. в справочном руководстве.394395### 15.17.1.9. Передача указателей (или: передача параметров по ссылке)396397Иногда функция C API ожидает в качестве параметра *указатель* на тип данных, обычно для записи в соответствующее место или если данные слишком велики для передачи по значению. Это также называется *передачей параметров по ссылке*.398399[`ctypes`](https://python-all.ru/2.7/library/ctypes.html#module-ctypes) экспортирует функцию [`byref()`](https://python-all.ru/2.7/library/ctypes.html#ctypes.byref), которая используется для передачи параметров по ссылке. Того же эффекта можно достичь с помощью функции [`pointer()`](https://python-all.ru/2.7/library/ctypes.html#ctypes.pointer), хотя [`pointer()`](https://python-all.ru/2.7/library/ctypes.html#ctypes.pointer) выполняет гораздо больше работы, так как создаёт реальный объект-указатель, поэтому быстрее использовать [`byref()`](https://python-all.ru/2.7/library/ctypes.html#ctypes.byref), если сам объект указателя в Python не нужен:400401```python402>>> i = c_int()403>>> f = c_float()404>>> s = create_string_buffer('\000' * 32)405>>> print i.value, f.value, repr(s.value)4060 0.0 ''407>>> libc.sscanf("1 3.14 Hello", "%d %f %s",408...             byref(i), byref(f), s)4093410>>> print i.value, f.value, repr(s.value)4111 3.1400001049 'Hello'412>>>413```414415### 15.17.1.10. Структуры и объединения416417Структуры и объединения должны наследоваться от базовых классов [`Structure`](https://python-all.ru/2.7/library/ctypes.html#ctypes.Structure) и [`Union`](https://python-all.ru/2.7/library/ctypes.html#ctypes.Union), которые определены в модуле [`ctypes`](https://python-all.ru/2.7/library/ctypes.html#module-ctypes). Каждый подкласс должен определить атрибут `_fields_`. `_fields_` должен быть списком *2-кортежей*, содержащих *имя поля* и *тип поля*.418419Тип поля должен быть типом [`ctypes`](https://python-all.ru/2.7/library/ctypes.html#module-ctypes), таким как [`c_int`](https://python-all.ru/2.7/library/ctypes.html#ctypes.c_int), или любым другим производным типом [`ctypes`](https://python-all.ru/2.7/library/ctypes.html#module-ctypes): структура, объединение, массив, указатель.420421Вот простой пример структуры POINT, которая содержит два целых числа с именами *x* и *y*, а также показывает, как инициализировать структуру в конструкторе:422423```python424>>> from ctypes import *425>>> class POINT(Structure):426...     _fields_ = [("x", c_int),427...                 ("y", c_int)]428...429>>> point = POINT(10, 20)430>>> print point.x, point.y43110 20432>>> point = POINT(y=5)433>>> print point.x, point.y4340 5435>>> POINT(1, 2, 3)436Traceback (most recent call last):437  File "<stdin>", line 1, in <module>438TypeError: too many initializers439>>>440```441442Однако можно создавать гораздо более сложные структуры. Структура может сама содержать другие структуры, используя структуру в качестве типа поля.443444Вот структура RECT, которая содержит две точки с именами *upperleft* и *lowerright*:445446```python447>>> class RECT(Structure):448...     _fields_ = [("upperleft", POINT),449...                 ("lowerright", POINT)]450...451>>> rc = RECT(point)452>>> print rc.upperleft.x, rc.upperleft.y4530 5454>>> print rc.lowerright.x, rc.lowerright.y4550 0456>>>457```458459Вложенные структуры также можно инициализировать в конструкторе несколькими способами:460461```python462>>> r = RECT(POINT(1, 2), POINT(3, 4))463>>> r = RECT((1, 2), (3, 4))464```465466полей [descriptor](https://python-all.ru/2.7/glossary.html#term-descriptor) можно получить из *класса*; они полезны для отладки, так как предоставляют полезную информацию:467468```python469>>> print POINT.x470<Field type=c_long, ofs=0, size=4>471>>> print POINT.y472<Field type=c_long, ofs=4, size=4>473>>>474```475476> **Предупреждение**477>478> [`ctypes`](https://python-all.ru/2.7/library/ctypes.html#module-ctypes) не поддерживает передачу объединений или структур с битовыми полями в функции по значению. Хотя это может работать на 32-битной x86, библиотека не гарантирует работу в общем случае. Объединения и структуры с битовыми полями всегда следует передавать в функции по указателю.479480### 15.17.1.11. Выравнивание структур/объединений и порядок байтов481482По умолчанию поля Structure и Union выравниваются так же, как это делает C компилятор. Можно переопределить это поведение, указав атрибут класса `_pack_` в определении подкласса. Он должен быть целым положительным числом и задает максимальное выравнивание для полей. Именно это и делает `#pragma pack(n)` в MSVC.483484[`ctypes`](https://python-all.ru/2.7/library/ctypes.html#module-ctypes) использует собственный порядок байт для Structures и Unions. Для создания структур с нестандартным порядком байт можно использовать один из базовых классов [`BigEndianStructure`](https://python-all.ru/2.7/library/ctypes.html#ctypes.BigEndianStructure), [`LittleEndianStructure`](https://python-all.ru/2.7/library/ctypes.html#ctypes.LittleEndianStructure), `BigEndianUnion` и `LittleEndianUnion`. Эти классы не могут содержать поля-указатели.485486### 15.17.1.12. Битовые поля в структурах и объединениях487488Можно создавать структуры и объединения, содержащие битовые поля. Битовые поля возможны только для целочисленных полей, ширина бита задается третьим элементом в кортежах `_fields_`:489490```python491>>> class Int(Structure):492...     _fields_ = [("first_16", c_int, 16),493...                 ("second_16", c_int, 16)]494...495>>> print Int.first_16496<Field type=c_long, ofs=0:0, bits=16>497>>> print Int.second_16498<Field type=c_long, ofs=0:16, bits=16>499>>>500```501502### 15.17.1.13. Массивы503504Массивы – это последовательности, содержащие фиксированное количество экземпляров одного типа.505506Рекомендуемый способ создания типов массивов – умножение типа данных на положительное целое число:507508```python509TenPointsArrayType = POINT * 10510```511512Вот пример несколько искусственного типа данных – структуры, содержащей 4 точки среди прочего:513514```python515>>> from ctypes import *516>>> class POINT(Structure):517...     _fields_ = ("x", c_int), ("y", c_int)518...519>>> class MyStruct(Structure):520...     _fields_ = [("a", c_int),521...                 ("b", c_float),522...                 ("point_array", POINT * 4)]523>>>524>>> print len(MyStruct().point_array)5254526>>>527```528529Экземпляры создаются обычным способом – вызовом класса:530531```python532arr = TenPointsArrayType()533for pt in arr:534    print pt.x, pt.y535```536537Приведенный выше код выводит серию строк `0 0`, потому что содержимое массива инициализируется нулями.538539Можно также указать инициализаторы правильного типа:540541```python542>>> from ctypes import *543>>> TenIntegers = c_int * 10544>>> ii = TenIntegers(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)545>>> print ii546<c_long_Array_10 object at 0x...>547>>> for i in ii: print i,548...5491 2 3 4 5 6 7 8 9 10550>>>551```552553### 15.17.1.14. Указатели554555Экземпляры указателей создаются вызовом функции [`pointer()`](https://python-all.ru/2.7/library/ctypes.html#ctypes.pointer) для типа [`ctypes`](https://python-all.ru/2.7/library/ctypes.html#module-ctypes):556557```python558>>> from ctypes import *559>>> i = c_int(42)560>>> pi = pointer(i)561>>>562```563564Экземпляры указателей имеют атрибут [`contents`](https://python-all.ru/2.7/library/ctypes.html#ctypes._Pointer.contents), который возвращает объект, на который указывает указатель, – объект `i` выше:565566```python567>>> pi.contents568c_long(42)569>>>570```571572Обратите внимание, что [`ctypes`](https://python-all.ru/2.7/library/ctypes.html#module-ctypes) не поддерживает OOR (возврат исходного объекта); он создает новый, эквивалентный объект каждый раз при получении атрибута:573574```python575>>> pi.contents is i576False577>>> pi.contents is pi.contents578False579>>>580```581582Присваивание другого экземпляра [`c_int`](https://python-all.ru/2.7/library/ctypes.html#ctypes.c_int) атрибуту contents указателя заставит указатель указывать на область памяти, где этот экземпляр хранится:583584```python585>>> i = c_int(99)586>>> pi.contents = i587>>> pi.contents588c_long(99)589>>>590```591592Экземпляры указателей также можно индексировать целыми числами:593594```python595>>> pi[0]59699597>>>598```599600Присваивание целочисленному индексу изменяет значение, на которое указывает указатель:601602```python603>>> print i604c_long(99)605>>> pi[0] = 22606>>> print i607c_long(22)608>>>609```610611It 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.612613За кулисами функция [`pointer()`](https://python-all.ru/2.7/library/ctypes.html#ctypes.pointer) делает нечто большее, чем просто создание экземпляров указателей: сначала необходимо создать *типы* указателей. Это делается с помощью функции [`POINTER()`](https://python-all.ru/2.7/library/ctypes.html#ctypes.POINTER), которая принимает любой тип [`ctypes`](https://python-all.ru/2.7/library/ctypes.html#module-ctypes) и возвращает новый тип:614615```python616>>> PI = POINTER(c_int)617>>> PI618<class 'ctypes.LP_c_long'>619>>> PI(42)620Traceback (most recent call last):621  File "<stdin>", line 1, in <module>622TypeError: expected c_long instead of int623>>> PI(c_int(42))624<ctypes.LP_c_long object at 0x...>625>>>626```627628Вызов типа указателя без аргументов создаёт нулевой указатель `NULL`. Нулевые указатели `NULL` имеют `False` ложное булево значение:629630```python631>>> null_ptr = POINTER(c_int)()632>>> print bool(null_ptr)633False634>>>635```636637[`ctypes`](https://python-all.ru/2.7/library/ctypes.html#module-ctypes) проверяет на `NULL` при разыменовании указателей (но разыменование недействительных не-`NULL` указателей приведёт к аварийному завершению Python):638639```python640>>> null_ptr[0]641Traceback (most recent call last):642    ....643ValueError: NULL pointer access644>>>645646>>> null_ptr[0] = 1234647Traceback (most recent call last):648    ....649ValueError: NULL pointer access650>>>651```652653### 15.17.1.15. Преобразования типов654655Обычно ctypes выполняет строгую проверку типов. Это означает, что если `POINTER(c_int)` указан в `argtypes` списке аргументов функции или в качестве типа поля структуры, принимаются только экземпляры точно того же типа. Из этого правила есть несколько исключений, когда ctypes принимает другие объекты. Например, можно передать совместимые экземпляры массивов вместо типов указателей. Так, для `POINTER(c_int)` ctypes принимает массив c\_int:656657```python658>>> class Bar(Structure):659...     _fields_ = [("count", c_int), ("values", POINTER(c_int))]660...661>>> bar = Bar()662>>> bar.values = (c_int * 3)(1, 2, 3)663>>> bar.count = 3664>>> for i in range(bar.count):665...     print bar.values[i]666...667166826693670>>>671```672673Кроме того, если аргумент функции явно объявлен как тип указателя (например, `POINTER(c_int)`) в `argtypes`, в функцию можно передать объект типа, на который указывает указатель (в данном случае `c_int`). В этом случае ctypes автоматически применит необходимое преобразование [`byref()`](https://python-all.ru/2.7/library/ctypes.html#ctypes.byref).674675Чтобы установить поле типа POINTER в `NULL`, можно присвоить `None`:676677```python678>>> bar.values = None679>>>680```681682Иногда встречаются экземпляры несовместимых типов. В C можно привести один тип к другому. [`ctypes`](https://python-all.ru/2.7/library/ctypes.html#module-ctypes) предоставляет функцию [`cast()`](https://python-all.ru/2.7/library/ctypes.html#ctypes.cast), которую можно использовать аналогичным образом. Структура `Bar`, определённая выше, принимает указатели `POINTER(c_int)` или массивы [`c_int`](https://python-all.ru/2.7/library/ctypes.html#ctypes.c_int) для своего поля `values`, но не экземпляры других типов:683684```python685>>> bar.values = (c_byte * 4)()686Traceback (most recent call last):687  File "<stdin>", line 1, in <module>688TypeError: incompatible types, c_byte_Array_4 instance instead of LP_c_long instance689>>>690```691692Для таких случаев удобна функция [`cast()`](https://python-all.ru/2.7/library/ctypes.html#ctypes.cast).693694Функцию [`cast()`](https://python-all.ru/2.7/library/ctypes.html#ctypes.cast) можно использовать для приведения экземпляра ctypes к указателю на другой тип данных ctypes. [`cast()`](https://python-all.ru/2.7/library/ctypes.html#ctypes.cast) принимает два параметра: объект ctypes, который является или может быть преобразован в указатель какого-либо вида, и тип указателя ctypes. Она возвращает экземпляр второго аргумента, который ссылается на тот же блок памяти, что и первый аргумент:695696```python697>>> a = (c_byte * 4)()698>>> cast(a, POINTER(c_int))699<ctypes.LP_c_long object at ...>700>>>701```702703Таким образом, [`cast()`](https://python-all.ru/2.7/library/ctypes.html#ctypes.cast) можно использовать для присваивания полю `values` структуры `Bar`:704705```python706>>> bar = Bar()707>>> bar.values = cast((c_byte * 4)(), POINTER(c_int))708>>> print bar.values[0]7090710>>>711```712713### 15.17.1.16. Неполные типы714715*Неполные типы* – это структуры, объединения или массивы, члены которых ещё не определены. В C они задаются опережающими объявлениями, которые определяются позже:716717```python718struct cell; /* forward declaration */719720struct cell {721    char *name;722    struct cell *next;723};724```725726Прямой перевод в код ctypes выглядел бы так, но это не работает:727728```python729>>> class cell(Structure):730...     _fields_ = [("name", c_char_p),731...                 ("next", POINTER(cell))]732...733Traceback (most recent call last):734  File "<stdin>", line 1, in <module>735  File "<stdin>", line 2, in cell736NameError: name 'cell' is not defined737>>>738```739740поскольку новый `class cell` недоступен в самом определении класса.\\nВ [`ctypes`](https://python-all.ru/2.7/library/ctypes.html#module-ctypes) мы можем определить класс `cell` и установить атрибут `_fields_`\\nпозже, после определения класса:741742```python743>>> from ctypes import *744>>> class cell(Structure):745...     pass746...747>>> cell._fields_ = [("name", c_char_p),748...                  ("next", POINTER(cell))]749>>>750```751752Попробуем. Создадим два экземпляра `cell`, сделаем так, чтобы они указывали друг на друга, и несколько раз пройдем по цепочке указателей:753754```python755>>> c1 = cell()756>>> c1.name = "foo"757>>> c2 = cell()758>>> c2.name = "bar"759>>> c1.next = pointer(c2)760>>> c2.next = pointer(c1)761>>> p = c1762>>> for i in range(8):763...     print p.name,764...     p = p.next[0]765...766foo bar foo bar foo bar foo bar767>>>768```769770### 15.17.1.17. Функции обратного вызова771772[`ctypes`](https://python-all.ru/2.7/library/ctypes.html#module-ctypes) позволяет создавать указатели на вызываемые функции C из вызываемых объектов Python. Их иногда называют *функциями обратного вызова*.773774Сначала необходимо создать класс для функции обратного вызова. Этот класс знает соглашение вызова, тип возвращаемого значения, а также количество и типы аргументов, которые будет получать эта функция.775776Фабричная функция CFUNCTYPE создаёт типы для функций обратного вызова с использованием обычного соглашения вызова cdecl, а на Windows фабричная функция WINFUNCTYPE создаёт типы для функций обратного вызова с использованием соглашения вызова stdcall.777778Обе эти фабричные функции вызываются с типом результата в качестве первого аргумента, а ожидаемые типы аргументов функции обратного вызова передаются как остальные аргументы.779780Я приведу здесь пример, использующий функцию `qsort()` из стандартной библиотеки C; она используется для сортировки элементов с помощью функции обратного вызова. `qsort()` будет использоваться для сортировки массива целых чисел:781782```python783>>> IntArray5 = c_int * 5784>>> ia = IntArray5(5, 1, 7, 33, 99)785>>> qsort = libc.qsort786>>> qsort.restype = None787>>>788```789790`qsort()` должна вызываться с указателем на сортируемые данные, количеством элементов в массиве данных, размером одного элемента и указателем на функцию сравнения – обратный вызов. Затем обратный вызов будет вызываться с двумя указателями на элементы и должен вернуть отрицательное целое число, если первый элемент меньше второго, ноль, если они равны, и положительное целое число в противном случае.791792Итак, наша функция обратного вызова получает указатели на целые числа и должна вернуть целое число. Сначала создаётся `type` для функции обратного вызова:793794```python795>>> CMPFUNC = CFUNCTYPE(c_int, POINTER(c_int), POINTER(c_int))796>>>797```798799Для первой реализации функции обратного вызова мы просто выводим полученные аргументы и возвращаем 0 (итеративная разработка ;-)):800801```python802>>> def py_cmp_func(a, b):803...     print "py_cmp_func", a, b804...     return 0805...806>>>807```808809Создайте вызываемый из C обратный вызов:810811```python812>>> cmp_func = CMPFUNC(py_cmp_func)813>>>814```815816И мы готовы начать:817818```python819>>> qsort(ia, len(ia), sizeof(c_int), cmp_func) 820py_cmp_func <ctypes.LP_c_long object at 0x00...> <ctypes.LP_c_long object at 0x00...>821py_cmp_func <ctypes.LP_c_long object at 0x00...> <ctypes.LP_c_long object at 0x00...>822py_cmp_func <ctypes.LP_c_long object at 0x00...> <ctypes.LP_c_long object at 0x00...>823py_cmp_func <ctypes.LP_c_long object at 0x00...> <ctypes.LP_c_long object at 0x00...>824py_cmp_func <ctypes.LP_c_long object at 0x00...> <ctypes.LP_c_long object at 0x00...>825py_cmp_func <ctypes.LP_c_long object at 0x00...> <ctypes.LP_c_long object at 0x00...>826py_cmp_func <ctypes.LP_c_long object at 0x00...> <ctypes.LP_c_long object at 0x00...>827py_cmp_func <ctypes.LP_c_long object at 0x00...> <ctypes.LP_c_long object at 0x00...>828py_cmp_func <ctypes.LP_c_long object at 0x00...> <ctypes.LP_c_long object at 0x00...>829py_cmp_func <ctypes.LP_c_long object at 0x00...> <ctypes.LP_c_long object at 0x00...>830>>>831```832833Мы знаем, как получить доступ к содержимому указателя, поэтому переопределим наш колбэк:834835```python836>>> def py_cmp_func(a, b):837...     print "py_cmp_func", a[0], b[0]838...     return 0839...840>>> cmp_func = CMPFUNC(py_cmp_func)841>>>842```843844Вот что мы получаем в Windows:845846```python847>>> qsort(ia, len(ia), sizeof(c_int), cmp_func) 848py_cmp_func 7 1849py_cmp_func 33 1850py_cmp_func 99 1851py_cmp_func 5 1852py_cmp_func 7 5853py_cmp_func 33 5854py_cmp_func 99 5855py_cmp_func 7 99856py_cmp_func 33 99857py_cmp_func 7 33858>>>859```860861Забавно, что на linux функция сортировки, похоже, работает гораздо эффективнее – она делает меньше сравнений:862863```python864>>> qsort(ia, len(ia), sizeof(c_int), cmp_func)  865py_cmp_func 5 1866py_cmp_func 33 99867py_cmp_func 7 33868py_cmp_func 5 7869py_cmp_func 1 7870>>>871```872873Ах, мы почти закончили! Последний шаг – собственно сравнить два элемента и вернуть полезный результат:874875```python876>>> def py_cmp_func(a, b):877...     print "py_cmp_func", a[0], b[0]878...     return a[0] - b[0]879...880>>>881```882883Финальный запуск в Windows:884885```python886>>> qsort(ia, len(ia), sizeof(c_int), CMPFUNC(py_cmp_func)) 887py_cmp_func 33 7888py_cmp_func 99 33889py_cmp_func 5 99890py_cmp_func 1 99891py_cmp_func 33 7892py_cmp_func 1 33893py_cmp_func 5 33894py_cmp_func 5 7895py_cmp_func 1 7896py_cmp_func 5 1897>>>898```899900и в Linux:901902```python903>>> qsort(ia, len(ia), sizeof(c_int), CMPFUNC(py_cmp_func)) 904py_cmp_func 5 1905py_cmp_func 33 99906py_cmp_func 7 33907py_cmp_func 1 7908py_cmp_func 5 7909>>>910```911912Довольно интересно заметить, что функция `qsort()` в Windows требует больше сравнений, чем в Linux!913914Как легко проверить, наш массив теперь отсортирован:915916```python917>>> for i in ia: print i,918...9191 5 7 33 99920>>>921```922923> **Примечание**924>925> Необходимо сохранять ссылки на объекты [`CFUNCTYPE()`](https://python-all.ru/2.7/library/ctypes.html#ctypes.CFUNCTYPE), пока они используются из кода на C. [`ctypes`](https://python-all.ru/2.7/library/ctypes.html#module-ctypes) этого не делает, и если не сохранять, они могут быть собраны сборщиком мусора, что приведет к краху программы при вызове колбэка.926>927> Также обратите внимание, что если функция обратного вызова вызывается в потоке, созданном вне контроля Python (например, внешним кодом, вызывающим колбэк), ctypes создает новый фиктивный поток Python при каждом вызове. Такое поведение корректно для большинства целей, но означает, что значения, сохраненные с помощью [`threading.local`](https://python-all.ru/2.7/library/threading.html#threading.local), *не* будут сохраняться между разными колбэками, даже если эти вызовы производятся из одного и того же потока C.928929### 15.17.1.18. Доступ к значениям, экспортируемым из DLL930931Некоторые разделяемые библиотеки экспортируют не только функции, но и переменные. Примером из самой библиотеки Python является `Py_OptimizeFlag` – целое число, равное 0, 1 или 2 в зависимости от флага [`-O`](https://python-all.ru/2.7/using/cmdline.html#cmdoption-o) или [`-OO`](https://python-all.ru/2.7/using/cmdline.html#cmdoption-oo), заданного при запуске.932933[`ctypes`](https://python-all.ru/2.7/library/ctypes.html#module-ctypes) может получать доступ к таким значениям с помощью методов класса `in_dll()` соответствующего типа. *pythonapi* – это предопределенный символ, предоставляющий доступ к C API Python:934935```python936>>> opt_flag = c_int.in_dll(pythonapi, "Py_OptimizeFlag")937>>> print opt_flag938c_long(0)939>>>940```941942Если бы интерпретатор был запущен с [`-O`](https://python-all.ru/2.7/using/cmdline.html#cmdoption-o), пример вывел бы\\n`c_long(1)` или `c_long(2)`, если бы был указан [`-OO`](https://python-all.ru/2.7/using/cmdline.html#cmdoption-oo).943944Расширенный пример, также демонстрирующий использование указателей, обращается к указателю `PyImport_FrozenModules`, экспортируемому Python.945946Цитируя документацию Python: *Этот указатель инициализируется так, чтобы указывать на массив записей «struct \_frozen», завершающийся записью, все члены которой равны NULL или нулю. При импорте замороженного модуля он ищется в этой таблице. Сторонний код может использовать это для динамического создания набора замороженных модулей.*947948Таким образом, манипуляции с этим указателем могут оказаться полезными. Чтобы ограничить размер примера, мы показываем только то, как эту таблицу можно прочитать с помощью [`ctypes`](https://python-all.ru/2.7/library/ctypes.html#module-ctypes):949950```python951>>> from ctypes import *952>>>953>>> class struct_frozen(Structure):954...     _fields_ = [("name", c_char_p),955...                 ("code", POINTER(c_ubyte)),956...                 ("size", c_int)]957...958>>>959```960961Мы определили тип данных `struct _frozen`, чтобы получить указатель на таблицу:962963```python964>>> FrozenTable = POINTER(struct_frozen)965>>> table = FrozenTable.in_dll(pythonapi, "PyImport_FrozenModules")966>>>967```968969Поскольку `table` – это `pointer` на массив записей `struct_frozen`, мы можем перебирать его, но нужно убедиться, что цикл завершается, потому что у указателей нет размера. Рано или поздно это, вероятно, приведет к сбою с нарушением доступа или чем-то подобным, поэтому лучше выйти из цикла, когда встретится запись NULL:970971```python972>>> for item in table:973...     print item.name, item.size974...     if item.name is None:975...         break976...977__hello__ 104978__phello__ -104979__phello__.spam 104980None 0981>>>982```983984Тот факт, что стандартный Python содержит замороженный модуль и замороженный пакет (обозначается отрицательным элементом size), не широко известен, это используется только для тестирования. Попробуйте, например, с `import __hello__`.985986### 15.17.1.19. Неожиданности987988В [`ctypes`](https://python-all.ru/2.7/library/ctypes.html#module-ctypes) есть некоторые граничные случаи, когда ожидаемое поведение может не совпадать с действительным.989990Рассмотрим следующий пример:991992```python993>>> from ctypes import *994>>> class POINT(Structure):995...     _fields_ = ("x", c_int), ("y", c_int)996...997>>> class RECT(Structure):998...     _fields_ = ("a", POINT), ("b", POINT)999...1000>>> p1 = POINT(1, 2)1001>>> p2 = POINT(3, 4)1002>>> rc = RECT(p1, p2)1003>>> print rc.a.x, rc.a.y, rc.b.x, rc.b.y10041 2 3 41005>>> # теперь поменять точки местами1006>>> rc.a, rc.b = rc.b, rc.a1007>>> print rc.a.x, rc.a.y, rc.b.x, rc.b.y10083 4 3 41009>>>1010```10111012Хм. Мы, безусловно, ожидали, что последний оператор выведет `3 4 1 2`. Что произошло? Вот шаги выполнения строки `rc.a, rc.b = rc.b, rc.a` выше:10131014```python1015>>> temp0, temp1 = rc.b, rc.a1016>>> rc.a = temp01017>>> rc.b = temp11018>>>1019```10201021Обратите внимание, что `temp0` и `temp1` – это объекты, все еще использующие внутренний буфер объекта `rc` выше. Таким образом, выполнение `rc.a = temp0` копирует содержимое буфера `temp0` в буфер `rc`. Это, в свою очередь, изменяет содержимое `temp1`. Поэтому последнее присваивание `rc.b = temp1` не дает ожидаемого эффекта.10221023Имейте в виду, что получение подобъектов из Structure, Unions и Arrays не *копирует* подобъект, а возвращает объект-обертку, обращающийся к базовому буферу корневого объекта.10241025Еще один пример, который может вести себя не так, как ожидается:10261027```python1028>>> s = c_char_p()1029>>> s.value = "abc def ghi"1030>>> s.value1031'abc def ghi'1032>>> s.value is s.value1033False1034>>>1035```10361037Почему выводится `False`? Экземпляры ctypes – это объекты, содержащие блок памяти и несколько [дескрипторов](https://python-all.ru/2.7/glossary.html#term-descriptor), обращающихся к содержимому памяти. Сохранение объекта Python в блоке памяти не сохраняет сам объект, вместо этого сохраняется `contents` объекта. При повторном доступе к содержимому каждый раз создается новый объект Python!10381039### 15.17.1.20. Типы данных переменного размера10401041[`ctypes`](https://python-all.ru/2.7/library/ctypes.html#module-ctypes) предоставляет некоторую поддержку массивов и структур переменного размера.10421043Функция [`resize()`](https://python-all.ru/2.7/library/ctypes.html#ctypes.resize) может использоваться для изменения размера буфера памяти существующего объекта ctypes. Функция принимает объект в качестве первого аргумента и запрошенный размер в байтах в качестве второго аргумента. Блок памяти не может быть уменьшен меньше естественного блока памяти, заданного типом объекта; при попытке этого вызывается [`ValueError`](https://python-all.ru/2.7/library/exceptions.html#exceptions.ValueError):10441045```python1046>>> short_array = (c_short * 4)()1047>>> print sizeof(short_array)104881049>>> resize(short_array, 4)1050Traceback (most recent call last):1051    ...1052ValueError: minimum size is 81053>>> resize(short_array, 32)1054>>> sizeof(short_array)1055321056>>> sizeof(type(short_array))105781058>>>1059```10601061Это хорошо и замечательно, но как получить доступ к дополнительным элементам, содержащимся в этом массиве? Поскольку тип по-прежнему знает только о 4 элементах, при попытке доступа к другим элементам возникают ошибки:10621063```python1064>>> short_array[:]1065[0, 0, 0, 0]1066>>> short_array[7]1067Traceback (most recent call last):1068    ...1069IndexError: invalid index1070>>>1071```10721073Другой способ использования типов данных переменного размера с [`ctypes`](https://python-all.ru/2.7/library/ctypes.html#module-ctypes) – воспользоваться динамической природой Python и (пере-)определять тип данных после того, как требуемый размер уже известен, в каждом конкретном случае.10741075## 15.17.2. Справочник по ctypes10761077### 15.17.2.1. Поиск разделяемых библиотек10781079При программировании на компилируемом языке к разделяемым библиотекам обращаются при компиляции/компоновке программы и при ее запуске.10801081Назначение функции `find_library()` – найти библиотеку способом, аналогичным используемому компилятором (на платформах с несколькими версиями разделяемой библиотеки должна загружаться самая новая), в то время как загрузчики библиотек ctypes действуют как при запуске программы и вызывают загрузчик времени выполнения напрямую.10821083Модуль `ctypes.util` предоставляет функцию, которая может помочь определить, какую библиотеку загрузить.10841085#### `ctypes.util.find_library(name)`10861087Пытается найти библиотеку и возвращает путь к файлу. *имя* – это имя библиотеки без префикса, например *lib*, суффикса, например `.so`, `.dylib`, и номера версии (такая форма используется для опции компоновщика POSIX `-l`). Если библиотеку не удается найти, возвращает `None`.10881089Точное поведение зависит от системы.10901091В Linux `find_library()` пытается запустить внешние программы (`/sbin/ldconfig`, `gcc` и `objdump`) для поиска файла библиотеки. Она возвращает имя файла библиотеки. Вот несколько примеров:10921093```python1094>>> from ctypes.util import find_library1095>>> find_library("m")1096'libm.so.6'1097>>> find_library("c")1098'libc.so.6'1099>>> find_library("bz2")1100'libbz2.so.1.0'1101>>>1102```11031104В OS X `find_library()` перебирает несколько предопределённых схем именования и путей для поиска библиотеки и возвращает полный путь к файлу в случае успеха:11051106```python1107>>> from ctypes.util import find_library1108>>> find_library("c")1109'/usr/lib/libc.dylib'1110>>> find_library("m")1111'/usr/lib/libm.dylib'1112>>> find_library("bz2")1113'/usr/lib/libbz2.dylib'1114>>> find_library("AGL")1115'/System/Library/Frameworks/AGL.framework/AGL'1116>>>1117```11181119В Windows `find_library()` выполняет поиск по системному пути поиска и возвращает полный путь, но поскольку нет предопределённой схемы именования, вызов наподобие `find_library("c")` завершится неудачей и вернёт `None`.11201121При обёртывании динамической библиотеки с помощью [`ctypes`](https://python-all.ru/2.7/library/ctypes.html#module-ctypes), возможно, *лучше* определить имя библиотеки на этапе разработки и жёстко задать его в модуле-обёртке, вместо использования `find_library()` для поиска библиотеки во время выполнения.11221123### 15.17.2.2. Загрузка разделяемых библиотек11241125Существует несколько способов загрузить разделяемые библиотеки в процесс Python. Один из способов – создать экземпляр одного из следующих классов:11261127#### `class ctypes.CDLL(name, mode=DEFAULT_MODE, handle=None, use_errno=False, use_last_error=False)`11281129Экземпляры этого класса представляют загруженные разделяемые библиотеки. Функции в этих библиотеках используют стандартное соглашение о вызовах C и, как предполагается, возвращают `int`.11301131#### `class ctypes.OleDLL(name, mode=DEFAULT_MODE, handle=None, use_errno=False, use_last_error=False)`11321133Только для Windows: экземпляры этого класса представляют загруженные разделяемые библиотеки,\\nфункции в этих библиотеках используют соглашение о вызове `stdcall` и, как предполагается,\\nвозвращают специфический для Windows код [`HRESULT`](https://python-all.ru/2.7/library/ctypes.html#ctypes.HRESULT). Значения [`HRESULT`](https://python-all.ru/2.7/library/ctypes.html#ctypes.HRESULT)\\nсодержат информацию о том, завершился ли вызов функции неудачей или успехом,\\nа также дополнительный код ошибки. Если возвращаемое значение указывает на\\nнеудачу, автоматически генерируется `WindowsError`.11341135#### `class ctypes.WinDLL(name, mode=DEFAULT_MODE, handle=None, use_errno=False, use_last_error=False)`11361137Только для Windows: экземпляры этого класса представляют загруженные разделяемые библиотеки, функции в этих библиотеках используют соглашение о вызовах `stdcall` и, по умолчанию, считаются возвращающими `int`.11381139В Windows CE используется только стандартное соглашение о вызовах; для удобства [`WinDLL`](https://python-all.ru/2.7/library/ctypes.html#ctypes.WinDLL) и [`OleDLL`](https://python-all.ru/2.7/library/ctypes.html#ctypes.OleDLL) используют стандартное соглашение о вызовах на этой платформе.11401141Глобальная блокировка интерпретатора Python [global interpreter lock](https://python-all.ru/2.7/glossary.html#term-global-interpreter-lock) освобождается перед вызовом любой функции, экспортируемой этими библиотеками, и снова захватывается после вызова.11421143#### `class ctypes.PyDLL(name, mode=DEFAULT_MODE, handle=None)`11441145Экземпляры этого класса ведут себя как экземпляры [`CDLL`](https://python-all.ru/2.7/library/ctypes.html#ctypes.CDLL), за исключением того, что GIL Python *не* освобождается во время вызова функции, и после выполнения функции проверяется флаг ошибки Python. Если флаг ошибки установлен, возбуждается исключение Python.11461147Таким образом, это полезно только для прямого вызова функций Python C API.11481149Все эти классы можно создать, вызвав их как минимум с одним аргументом –\\nпутем к разделяемой библиотеке. Если у вас уже есть дескриптор (handle) уже\\nзагруженной разделяемой библиотеки, его можно передать в качестве именованного\\nпараметра `handle`; в противном случае для загрузки библиотеки в процесс и\\nполучения дескриптора используется функция базовой платформы `dlopen` или `LoadLibrary`.11501151Параметр *mode* используется для указания способа загрузки библиотеки. Для подробностей обратитесь к man-странице *dlopen(3)*. В Windows *mode* игнорируется. В системах POSIX всегда добавляется RTLD\_NOW, и это не настраивается.11521153Параметр *use\_errno*, если установлен в true, включает механизм ctypes, позволяющий безопасно получать системный номер ошибки [`errno`](https://python-all.ru/2.7/library/errno.html#module-errno). [`ctypes`](https://python-all.ru/2.7/library/ctypes.html#module-ctypes) хранит в локальной копии потока системную переменную [`errno`](https://python-all.ru/2.7/library/errno.html#module-errno); если вызвать внешнюю функцию, созданную с `use_errno=True`, то значение [`errno`](https://python-all.ru/2.7/library/errno.html#module-errno) перед вызовом функции заменяется на приватную копию ctypes, то же самое происходит сразу после вызова функции.11541155Функция [`ctypes.get_errno()`](https://python-all.ru/2.7/library/ctypes.html#ctypes.get_errno) возвращает значение приватной копии ctypes, а функция [`ctypes.set_errno()`](https://python-all.ru/2.7/library/ctypes.html#ctypes.set_errno) изменяет приватную копию ctypes на новое значение и возвращает предыдущее значение.11561157Параметр *use\_last\_error*, если установлен в true, включает тот же механизм для кода ошибки Windows, который управляется функциями Windows API [`GetLastError()`](https://python-all.ru/2.7/library/ctypes.html#ctypes.GetLastError) и `SetLastError()`; [`ctypes.get_last_error()`](https://python-all.ru/2.7/library/ctypes.html#ctypes.get_last_error) и [`ctypes.set_last_error()`](https://python-all.ru/2.7/library/ctypes.html#ctypes.set_last_error) используются для запроса и изменения приватной копии кода ошибки Windows в ctypes.11581159Новое в версии 2.6: Добавлены необязательные параметры *use\_last\_error* и *use\_errno*.11601161#### `ctypes.RTLD_GLOBAL`11621163Флаг, используемый в качестве параметра *mode*. На платформах, где этот флаг недоступен, он определён как целочисленный ноль.11641165#### `ctypes.RTLD_LOCAL`11661167Флаг, используемый в качестве параметра *mode*. На платформах, где он недоступен, он совпадает с *RTLD\_GLOBAL*.11681169#### `ctypes.DEFAULT_MODE`11701171Режим по умолчанию, используемый для загрузки разделяемых библиотек. На OSX 10.3 это *RTLD\_GLOBAL*, в противном случае он совпадает с *RTLD\_LOCAL*.11721173Экземпляры этих классов не имеют открытых методов. Функции, экспортируемые общей библиотекой, можно получить как атрибуты или по индексу. Обратите внимание: доступ к функции через атрибут кэширует результат, поэтому при повторном обращении возвращается тот же самый объект каждый раз. С другой стороны, доступ по индексу каждый раз возвращает новый объект:11741175```python1176>>> libc.time == libc.time1177True1178>>> libc['time'] == libc['time']1179False1180```11811182Доступны следующие открытые атрибуты, их имена начинаются с подчёркивания, чтобы не конфликтовать с именами экспортируемых функций:11831184#### `PyDLL._handle`11851186Системный дескриптор, используемый для доступа к библиотеке.11871188#### `PyDLL._name`11891190Имя библиотеки, переданное в конструктор.11911192Разделяемые библиотеки также можно загружать, используя один из готовых объектов,\\nкоторые являются экземплярами класса [`LibraryLoader`](https://python-all.ru/2.7/library/ctypes.html#ctypes.LibraryLoader), либо вызвав метод\\n`LoadLibrary()`, либо обратившись к библиотеке как к атрибуту экземпляра загрузчика.11931194#### `class ctypes.LibraryLoader(dlltype)`11951196Класс, который загружает разделяемые библиотеки. *dlltype* должен быть одним из типов [`CDLL`](https://python-all.ru/2.7/library/ctypes.html#ctypes.CDLL), [`PyDLL`](https://python-all.ru/2.7/library/ctypes.html#ctypes.PyDLL), [`WinDLL`](https://python-all.ru/2.7/library/ctypes.html#ctypes.WinDLL) или [`OleDLL`](https://python-all.ru/2.7/library/ctypes.html#ctypes.OleDLL).11971198[`__getattr__()`](https://python-all.ru/2.7/reference/datamodel.html#object.__getattr__) обладает особым поведением: он позволяет загружать разделяемую библиотеку, обращаясь к ней как к атрибуту экземпляра загрузчика библиотек. Результат кэшируется, поэтому повторные обращения к атрибуту каждый раз возвращают одну и ту же библиотеку.11991200#### `LoadLibrary(name)`12011202Загружает разделяемую библиотеку в процесс и возвращает её. Этот метод всегда возвращает новый экземпляр библиотеки.12031204Доступны следующие готовые загрузчики библиотек:12051206#### `ctypes.cdll`12071208Создаёт экземпляры [`CDLL`](https://python-all.ru/2.7/library/ctypes.html#ctypes.CDLL).12091210#### `ctypes.windll`12111212Только для Windows: создаёт экземпляры [`WinDLL`](https://python-all.ru/2.7/library/ctypes.html#ctypes.WinDLL).12131214#### `ctypes.oledll`12151216Только для Windows: создаёт экземпляры [`OleDLL`](https://python-all.ru/2.7/library/ctypes.html#ctypes.OleDLL).12171218#### `ctypes.pydll`12191220Создаёт экземпляры [`PyDLL`](https://python-all.ru/2.7/library/ctypes.html#ctypes.PyDLL).12211222Для прямого доступа к C Python API доступен готовый к использованию объект общей библиотеки Python:12231224#### `ctypes.pythonapi`12251226Экземпляр [`PyDLL`](https://python-all.ru/2.7/library/ctypes.html#ctypes.PyDLL), предоставляющий функции Python C API в виде\\nатрибутов. Учтите, что предполагается, будто все эти функции возвращают C\\n`int`, но на деле это не всегда так, поэтому для их использования необходимо задать\\nправильный атрибут `restype`.12271228### 15.17.2.3. Внешние функции12291230Как объяснялось в предыдущем разделе, внешние функции можно получить как атрибуты загруженных разделяемых библиотек. Созданные таким образом объекты функций по умолчанию принимают любое количество аргументов, принимают любые экземпляры данных ctypes в качестве аргументов и возвращают тип результата по умолчанию, указанный загрузчиком библиотеки. Они являются экземплярами закрытого класса:12311232#### `class ctypes._FuncPtr`12331234Базовый класс для внешних функций, вызываемых из C.12351236Экземпляры внешних функций также являются C-совместимыми типами данных; они представляют указатели на функции C.12371238Это поведение можно настроить, присвоив значения специальным атрибутам объекта внешней функции.12391240#### `restype`12411242Назначьте тип ctypes для указания типа результата внешней функции.\\nИспользуйте `None` для `void` (функции, ничего не возвращающей).12431244Можно назначить вызываемый объект Python, не являющийся типом ctypes;\\nв этом случае считается, что функция возвращает C `int`, и этот вызываемый объект\\nбудет вызван с этим целым числом, что позволяет выполнить дальнейшую\\nобработку или проверку ошибок. Использование этого подхода устарело; для более гибкой\\nпостобработки или проверки ошибок используйте тип данных ctypes в качестве\\n[`restype`](https://python-all.ru/2.7/library/ctypes.html#ctypes._FuncPtr.restype) и назначьте вызываемый объект атрибуту [`errcheck`](https://python-all.ru/2.7/library/ctypes.html#ctypes._FuncPtr.errcheck).12451246#### `argtypes`12471248Назначьте кортеж типов ctypes, чтобы указать типы аргументов, которые принимает функция. Функции, использующие соглашение о вызове `stdcall`, могут быть вызваны только с тем же количеством аргументов, что и длина этого кортежа; функции, использующие C соглашение о вызове, также принимают дополнительные неопределённые аргументы.12491250Когда вызывается внешняя функция, каждый фактический аргумент передаётся методу класса `from_param()` элементов кортежа [`argtypes`](https://python-all.ru/2.7/library/ctypes.html#ctypes._FuncPtr.argtypes). Этот метод позволяет адаптировать аргумент к объекту, который принимает внешняя функция. Например, элемент [`c_char_p`](https://python-all.ru/2.7/library/ctypes.html#ctypes.c_char_p) в кортеже [`argtypes`](https://python-all.ru/2.7/library/ctypes.html#ctypes._FuncPtr.argtypes) преобразует строку Unicode, переданную как аргумент, в байтовую строку по правилам преобразования ctypes.12511252Новое: теперь можно помещать в argtypes элементы, которые не являются типами ctypes, но каждый элемент должен иметь метод `from_param()`, возвращающий значение, пригодное в качестве аргумента (целое число, строка, экземпляр ctypes). Это позволяет определять адаптеры, которые могут адаптировать пользовательские объекты в качестве параметров функции.12531254#### `errcheck`12551256Этому атрибуту присваивается функция Python или другой вызываемый объект. Вызываемый объект будет вызван с тремя и более аргументами:12571258#### `callable(result, func, arguments)`12591260*result* – это то, что возвращает внешняя функция, как указано атрибутом [`restype`](https://python-all.ru/2.7/library/ctypes.html#ctypes._FuncPtr.restype).12611262*func* – это сам объект внешней функции; это позволяет повторно использовать один и тот же вызываемый объект для проверки или последующей обработки результатов нескольких функций.12631264*arguments* – это кортеж, содержащий параметры, переданные вызову функции; это позволяет специализировать поведение на основе используемых аргументов.12651266Объект, возвращаемый этой функцией, будет возвращён из вызова внешней функции, но он также может проверить значение результата и возбудить исключение, если вызов внешней функции завершился неудачей.12671268#### `exception ctypes.ArgumentError`12691270Это исключение возникает, когда вызов внешней функции не может преобразовать один из переданных аргументов.12711272### 15.17.2.4. Прототипы функций12731274Внешние функции также можно создать, инстанцируя прототипы функций. Прототипы функций аналогичны прототипам функций в C; они описывают функцию (тип возвращаемого значения, типы аргументов, соглашение о вызове) без определения реализации. Фабричные функции необходимо вызывать с желаемым типом результата и типами аргументов функции.12751276#### `ctypes.CFUNCTYPE(restype, *argtypes, use_errno=False, use_last_error=False)`12771278Созданный прототип функции создаёт функции, использующие стандартное соглашение о вызове C. Функция освобождает GIL во время вызова. Если *use\_errno* установлен в true, приватная копия переменной [`errno`](https://python-all.ru/2.7/library/errno.html#module-errno) ctypes обменивается с реальным значением [`errno`](https://python-all.ru/2.7/library/errno.html#module-errno) до и после вызова; *use\_last\_error* делает то же самое для кода ошибки Windows.12791280Изменено в версии 2.6: Добавлены необязательные параметры *use\_errno* и *use\_last\_error*.12811282#### `ctypes.WINFUNCTYPE(restype, *argtypes, use_errno=False, use_last_error=False)`12831284Только для Windows: возвращаемый прототип функции создаёт функции, использующие соглашение о вызовах `stdcall`, за исключением Windows CE, где [`WINFUNCTYPE()`](https://python-all.ru/2.7/library/ctypes.html#ctypes.WINFUNCTYPE) совпадает с [`CFUNCTYPE()`](https://python-all.ru/2.7/library/ctypes.html#ctypes.CFUNCTYPE). Функция будет отпускать GIL во время вызова. *use\_errno* и *use\_last\_error* имеют тот же смысл, что и выше.12851286#### `ctypes.PYFUNCTYPE(restype, *argtypes)`12871288Созданный прототип функции создаёт функции, использующие соглашение о вызове Python. Функция *не* освобождает GIL во время вызова.12891290Прототипы функций, созданные этими фабричными функциями, могут быть созданы различными способами, в зависимости от типа и количества параметров в вызове:12911292> #### `prototype(address)`1293>1294> Возвращает внешнюю функцию по указанному адресу, который должен быть целым числом.1295>1296> #### `prototype(callable)`1297>1298> Создаёт вызываемую функцию C (функцию обратного вызова) из *вызываемого объекта* Python.1299>1300> #### `prototype(func_spec[, paramflags])`1301>1302> Возвращает внешнюю функцию, экспортируемую разделяемой библиотекой. *func\_spec* должен быть 2-кортежем `(name_or_ordinal, library)`. Первый элемент – это имя экспортируемой функции в виде строки или порядковый номер экспортируемой функции как небольшое целое число. Второй элемент – это экземпляр разделяемой библиотеки.1303>1304> #### `prototype(vtbl_index, name[, paramflags[, iid]])`1305>1306> Возвращает внешнюю функцию, которая будет вызывать метод COM. *vtbl\_index* – это индекс в таблице виртуальных функций, небольшое неотрицательное целое число. *name* – имя метода COM. *iid* – необязательный указатель на идентификатор интерфейса, используемый в расширенном отчёте об ошибках.1307>1308> Методы COM используют специальное соглашение о вызове: в дополнение к параметрам, указанным в кортеже `argtypes`, они требуют указатель на интерфейс COM в качестве первого аргумента.1309>1310> Необязательный параметр *paramflags* создаёт обёртки внешних функций с гораздо большей функциональностью, чем описано выше.1311>1312> *paramflags* должен быть кортежем той же длины, что и `argtypes`.1313>1314> Каждый элемент этого кортежа содержит дополнительную информацию о параметре; он должен быть кортежем, содержащим один, два или три элемента.1315>1316> Первый элемент – целое число, содержащее комбинацию флагов направления для параметра:1317>1318> > **1**1319> >1320> > Задаёт входной параметр функции.1321> >1322> > **2**1323> >1324> > Выходной параметр. Внешняя функция заполняет значение.1325> >1326> > **4**1327> >1328> > Входной параметр, по умолчанию равный нулю.1329>1330> Необязательный второй элемент – имя параметра в виде строки. Если он указан, внешнюю функцию можно вызывать с именованными параметрами.1331>1332> Необязательный третий элемент – значение по умолчанию для этого параметра.13331334Этот пример демонстрирует, как обернуть функцию Windows `MessageBoxA` так,\\nчтобы она поддерживала параметры по умолчанию и именованные аргументы. Объявление C из\\nзаголовочного файла Windows выглядит так:13351336```python1337WINUSERAPI int WINAPI1338MessageBoxA(1339    HWND hWnd,1340    LPCSTR lpText,1341    LPCSTR lpCaption,1342    UINT uType);1343```13441345Вот обёртка с помощью [`ctypes`](https://python-all.ru/2.7/library/ctypes.html#module-ctypes):13461347```python1348>>> from ctypes import c_int, WINFUNCTYPE, windll1349>>> from ctypes.wintypes import HWND, LPCSTR, UINT1350>>> prototype = WINFUNCTYPE(c_int, HWND, LPCSTR, LPCSTR, UINT)1351>>> paramflags = (1, "hwnd", 0), (1, "text", "Hi"), (1, "caption", None), (1, "flags", 0)1352>>> MessageBox = prototype(("MessageBoxA", windll.user32), paramflags)1353>>>1354```13551356Теперь внешнюю функцию MessageBox можно вызывать следующими способами:13571358```python1359>>> MessageBox()1360>>> MessageBox(text="Spam, spam, spam")1361>>> MessageBox(flags=2, text="foo bar")1362>>>1363```13641365Второй пример демонстрирует выходные параметры. Функция win32 `GetWindowRect` получает размеры указанного окна, копируя их в структуру `RECT`, которую должен предоставить вызывающий. Вот объявление на C:13661367```python1368WINUSERAPI BOOL WINAPI1369GetWindowRect(1370     HWND hWnd,1371     LPRECT lpRect);1372```13731374Вот обёртка с помощью [`ctypes`](https://python-all.ru/2.7/library/ctypes.html#module-ctypes):13751376```python1377>>> from ctypes import POINTER, WINFUNCTYPE, windll, WinError1378>>> from ctypes.wintypes import BOOL, HWND, RECT1379>>> prototype = WINFUNCTYPE(BOOL, HWND, POINTER(RECT))1380>>> paramflags = (1, "hwnd"), (2, "lprect")1381>>> GetWindowRect = prototype(("GetWindowRect", windll.user32), paramflags)1382>>>1383```13841385Функции с выходными параметрами автоматически возвращают значение выходного параметра, если он один, или кортеж значений выходных параметров, если их несколько; таким образом, при вызове функция GetWindowRect теперь возвращает экземпляр RECT.13861387Выходные параметры можно комбинировать с протоколом `errcheck` для дополнительной обработки выходных данных и проверки ошибок. Функция win32 API `GetWindowRect` возвращает `BOOL`, сигнализируя об успехе или неудаче, поэтому эта функция может выполнять проверку ошибок и возбуждать исключение при сбое вызова API:13881389```python1390>>> def errcheck(result, func, args):1391...     if not result:1392...         raise WinError()1393...     return args1394...1395>>> GetWindowRect.errcheck = errcheck1396>>>1397```13981399Если функция `errcheck` возвращает полученный кортеж аргументов без изменений, [`ctypes`](https://python-all.ru/2.7/library/ctypes.html#module-ctypes) продолжает обычную обработку выходных параметров. Если же требуется вернуть кортеж координат окна вместо экземпляра `RECT`, можно извлечь поля в функции и вернуть их – тогда обычная обработка выполняться не будет:14001401```python1402>>> def errcheck(result, func, args):1403...     if not result:1404...         raise WinError()1405...     rc = args[1]1406...     return rc.left, rc.top, rc.bottom, rc.right1407...1408>>> GetWindowRect.errcheck = errcheck1409>>>1410```14111412### 15.17.2.5. Вспомогательные функции14131414#### `ctypes.addressof(obj)`14151416Возвращает адрес буфера памяти в виде целого числа. *obj* должен быть экземпляром типа ctypes.14171418#### `ctypes.alignment(obj_or_type)`14191420Возвращает требования к выравниванию для типа ctypes. *obj\_or\_type* должен быть типом ctypes или его экземпляром.14211422#### `ctypes.byref(obj, offsetoffset])`14231424Возвращает легковесный указатель на *obj*, который должен быть экземпляром типа ctypes. Параметр *offset* по умолчанию равен нулю и должен быть целым числом, которое будет добавлено к внутреннему значению указателя.14251426`byref(obj, offset)` соответствует следующему коду на C:14271428```python1429(((char *)&obj) + offset)1430```14311432Возвращаемый объект может использоваться только как параметр вызова внешней функции. Он ведёт себя аналогично `pointer(obj)`, но создаётся гораздо быстрее.14331434Новое в версии 2.6: Добавлен необязательный аргумент *offset*.14351436#### `ctypes.cast(obj, type)`14371438Эта функция похожа на оператор приведения типа в C. Она возвращает новый экземпляр *type*, указывающий на тот же блок памяти, что и *obj*. *type* должен быть типом указателя, а *obj* – объектом, который может интерпретироваться как указатель.14391440#### `ctypes.create_string_buffer(init_or_size[, size])`14411442Эта функция создаёт изменяемый символьный буфер. Возвращаемый объект представляет собой массив ctypes из [`c_char`](https://python-all.ru/2.7/library/ctypes.html#ctypes.c_char).14431444*init\_or\_size* должен быть целым числом, задающим размер массива, или строкой, которая будет использоваться для инициализации элементов массива.14451446Если в качестве первого аргумента указана строка, буфер делается на один элемент больше длины строки, чтобы последним элементом массива был завершающий символ NUL. Вторым аргументом можно передать целое число, которое позволяет задать размер массива, если длина строки не должна использоваться.14471448Если первый параметр – строка в кодировке Unicode, она преобразуется в 8-битную строку по правилам преобразования ctypes.14491450#### `ctypes.create_unicode_buffer(init_or_size[, size])`14511452Эта функция создаёт изменяемый буфер символов Unicode. Возвращаемый объект представляет собой массив ctypes из [`c_wchar`](https://python-all.ru/2.7/library/ctypes.html#ctypes.c_wchar).14531454*init\_or\_size* должен быть целым числом, задающим размер массива, или строкой unicode, которая будет использоваться для инициализации элементов массива.14551456Если в качестве первого аргумента указана строка unicode, буфер делается на один элемент больше длины строки, чтобы последним элементом массива был завершающий символ NUL. Вторым аргументом можно передать целое число, которое позволяет задать размер массива, если длина строки не должна использоваться.14571458Если первый параметр – 8-битная строка, она преобразуется в строку unicode в соответствии с правилами преобразования ctypes.14591460#### `ctypes.DllCanUnloadNow()`14611462Только для Windows: эта функция является перехватчиком, который позволяет реализовывать внутрипроцессные COM-серверы с помощью ctypes. Она вызывается из функции DllCanUnloadNow, которую экспортирует DLL расширения \_ctypes.14631464#### `ctypes.DllGetClassObject()`14651466Только для Windows: эта функция является перехватчиком, который позволяет реализовывать внутрипроцессные COM-серверы с помощью ctypes. Она вызывается из функции DllGetClassObject, которую экспортирует DLL расширения `_ctypes`.14671468#### `ctypes.util.find_library(name)`14691470Пытается найти библиотеку и возвращает путь. *name* – это имя библиотеки без префиксов вроде `lib`, суффиксов вроде `.so`, `.dylib` или номера версии (именно такая форма используется для опции компоновщика в POSIX `-l`). Если библиотеку не удаётся найти, возвращает `None`.14711472Точное поведение зависит от системы.14731474Изменено в версии 2.6: Только Windows: `find_library("m")` или `find_library("c")` возвращают результат вызова `find_msvcrt()`.14751476#### `ctypes.util.find_msvcrt()`14771478Только для Windows: возвращает имя файла библиотеки времени выполнения VC, используемой Python и модулями расширения. Если имя библиотеки не удаётся определить, возвращается `None`.14791480Если необходимо освободить память, выделенную, например, модулем расширения с помощью вызова `free(void *)`, важно использовать функцию из той же библиотеки, которая выделила память.14811482Новое в версии 2.6.14831484#### `ctypes.FormatError([code])`14851486Только для Windows: возвращает текстовое описание кода ошибки *code*. Если код ошибки не указан, используется последний код ошибки, полученный вызовом функции Windows API GetLastError.14871488#### `ctypes.GetLastError()`14891490Только для Windows: Возвращает последний код ошибки, установленный Windows в вызывающем потоке. Эта функция вызывает непосредственно функцию Windows *GetLastError()*; она не возвращает внутреннюю для ctypes копию кода ошибки.14911492#### `ctypes.get_errno()`14931494Возвращает текущее значение приватной копии ctypes для системной переменной [`errno`](https://python-all.ru/2.7/library/errno.html#module-errno) в вызывающем потоке.14951496Новое в версии 2.6.14971498#### `ctypes.get_last_error()`14991500Только для Windows: возвращает текущее значение приватной для ctypes копии системной переменной `LastError` в вызывающем потоке.15011502Новое в версии 2.6.15031504#### `ctypes.memmove(dst, src, count)`15051506Аналогична стандартной библиотечной функции C memmove: копирует *count* байт из *src* в *dst*. *dst* и *src* должны быть целыми числами или экземплярами ctypes, которые можно преобразовать в указатели.15071508#### `ctypes.memset(dst, c, count)`15091510Аналогична стандартной библиотечной функции C memset: заполняет блок памяти по адресу *dst* *count* байтами значения *c*. *dst* должно быть целым числом, задающим адрес, или экземпляром ctypes.15111512#### `ctypes.POINTER(type)`15131514Эта фабричная функция создаёт и возвращает новый тип указателя ctypes. Типы\\nуказателей кэшируются и повторно используются внутри, поэтому многократный вызов этой функции является\\nдешёвым. *type* должен быть типом ctypes.15151516#### `ctypes.pointer(obj)`15171518Эта функция создаёт новый экземпляр указателя, указывающий на *obj*. Возвращаемый\\nобъект имеет тип `POINTER(type(obj))`.15191520Примечание: Если требуется просто передать указатель на объект в вызов внешней функции, следует использовать `byref(obj)`, что намного быстрее.15211522#### `ctypes.resize(obj, size)`15231524Эта функция изменяет размер внутреннего буфера памяти *obj*, который должен быть экземпляром типа ctypes. Уменьшить буфер ниже собственного размера типа объекта, заданного `sizeof(type(obj))`, невозможно, но увеличить буфер – можно.15251526#### `ctypes.set_conversion_mode(encoding, errors)`15271528Эта функция задаёт правила, которые объекты ctypes используют при преобразовании между 8-битными строками и строками unicode. *encoding* должен быть строкой, указывающей кодировку, например `'utf-8'` или `'mbcs'`; *errors* должен быть строкой, указывающей обработку ошибок при кодировании/декодировании. Примеры возможных значений: `"strict"`, `"replace"` или `"ignore"`.15291530[`set_conversion_mode()`](https://python-all.ru/2.7/library/ctypes.html#ctypes.set_conversion_mode) возвращает кортеж из двух элементов, содержащий предыдущие правила преобразования. В Windows начальные правила преобразования – `('mbcs', 'ignore')`, в других системах – `('ascii', 'strict')`.15311532#### `ctypes.set_errno(value)`15331534Устанавливает текущее значение приватной копии ctypes для системной переменной [`errno`](https://python-all.ru/2.7/library/errno.html#module-errno) в вызывающем потоке в *value* и возвращает предыдущее значение.15351536Новое в версии 2.6.15371538#### `ctypes.set_last_error(value)`15391540Только для Windows: устанавливает текущее значение приватной для ctypes копии системной переменной `LastError` в вызывающем потоке в *value* и возвращает предыдущее значение.15411542Новое в версии 2.6.15431544#### `ctypes.sizeof(obj_or_type)`15451546Возвращает размер в байтах буфера памяти типа или экземпляра ctypes. Делает то же, что и оператор C `sizeof`.15471548#### `ctypes.string_at(address[, size])`15491550Эта функция возвращает строку, начинающуюся с адреса памяти *address*. Если указан size, он используется как размер, в противном случае считается, что строка завершается нулевым символом.15511552#### `ctypes.WinError(code=None, descr=None)`15531554Только Windows: эта функция, вероятно, самая неудачно названная вещь в ctypes. Она создаёт экземпляр WindowsError. Если *code* не указан, вызывается `GetLastError` для определения кода ошибки. Если `descr` не указан, вызывается [`FormatError()`](https://python-all.ru/2.7/library/ctypes.html#ctypes.FormatError) для получения текстового описания ошибки.15551556#### `ctypes.wstring_at(address[, size])`15571558Эта функция возвращает широкую строку, начинающуюся с адреса памяти *address*, в виде строки unicode. Если указан *size*, он используется как количество символов строки, в противном случае считается, что строка завершается нулевым символом.15591560### 15.17.2.6. Типы данных15611562#### `class ctypes._CData`15631564Этот непубличный класс является общей базой для всех типов данных ctypes. В частности, все экземпляры типов ctypes содержат блок памяти, хранящий данные, совместимые с C; адрес этого блока возвращает вспомогательная функция [`addressof()`](https://python-all.ru/2.7/library/ctypes.html#ctypes.addressof). Ещё одна переменная экземпляра доступна как [`_objects`](https://python-all.ru/2.7/library/ctypes.html#ctypes._CData._objects); она содержит другие объекты Python, которые необходимо сохранять, если блок памяти содержит указатели.15651566Общие методы типов данных ctypes, все они являются методами класса (если точнее, это методы [метакласса](https://python-all.ru/2.7/glossary.html#term-metaclass)):15671568#### `from_buffer(source[, offset])`15691570Этот метод возвращает экземпляр ctypes, который разделяет буфер объекта *source*. Объект *source* должен поддерживать интерфейс буфера для записи. Необязательный параметр *offset* указывает смещение в буфере источника в байтах; по умолчанию ноль. Если буфер источника недостаточно велик, возникает исключение [`ValueError`](https://python-all.ru/2.7/library/exceptions.html#exceptions.ValueError).15711572Новое в версии 2.6.15731574#### `from_buffer_copy(source[, offset])`15751576Этот метод создаёт экземпляр ctypes, копируя буфер из объекта *source*, который должен быть читаемым. Необязательный параметр *offset* задаёт смещение в буфере источника в байтах; по умолчанию ноль. Если буфер источника недостаточно велик, возникает исключение [`ValueError`](https://python-all.ru/2.7/library/exceptions.html#exceptions.ValueError).15771578Новое в версии 2.6.15791580#### `from_address(address)`15811582Этот метод возвращает экземпляр типа ctypes, использующий память, указанную *address*, который должен быть целым числом.15831584#### `from_param(obj)`15851586Этот метод адаптирует *obj* к типу ctypes. Он вызывается с фактическим объектом, используемым при вызове внешней функции, когда этот тип присутствует в кортеже `argtypes` этой внешней функции; он должен возвращать объект, который можно использовать в качестве параметра вызова функции.15871588Все типы данных ctypes имеют реализацию этого метода класса по умолчанию, которая обычно возвращает *obj*, если он является экземпляром этого типа. Некоторые типы также принимают другие объекты.15891590#### `in_dll(library, name)`15911592Этот метод возвращает экземпляр типа ctypes, экспортируемый общей библиотекой. *name* – это имя символа, экспортирующего данные; *library* – загруженная общая библиотека.15931594Общие переменные экземпляра типов данных ctypes:15951596#### `_b_base_`15971598Иногда экземпляры данных ctypes не являются владельцами содержащегося в них блока памяти, а разделяют часть блока памяти базового объекта. Атрибут только для чтения [`_b_base_`](https://python-all.ru/2.7/library/ctypes.html#ctypes._CData._b_base_) – это корневой объект ctypes, владеющий блоком памяти.15991600#### `_b_needsfree_`16011602Эта переменная только для чтения равна true, когда экземпляр данных ctypes сам выделил блок памяти, и false в противном случае.16031604#### `_objects`16051606Этот элемент может быть `None` или словарём, содержащим объекты Python, которые необходимо удерживать в памяти, чтобы содержимое блока памяти оставалось валидным. Этот объект предоставляется только для отладки; не изменяйте содержимое этого словаря.16071608### 15.17.2.7. Фундаментальные типы данных16091610#### `class ctypes._SimpleCData`16111612Этот непубличный класс является базовым для всех фундаментальных типов данных ctypes. Он упоминается здесь, потому что содержит общие атрибуты фундаментальных типов данных ctypes. [`_SimpleCData`](https://python-all.ru/2.7/library/ctypes.html#ctypes._SimpleCData) является подклассом [`_CData`](https://python-all.ru/2.7/library/ctypes.html#ctypes._CData), поэтому наследует их методы и атрибуты.16131614Изменено в версии 2.6: Типы данных ctypes, которые не являются указателями и не содержат указателей, теперь можно сериализовать.16151616Экземпляры имеют один атрибут:16171618#### `value`16191620Этот атрибут содержит фактическое значение экземпляра. Для целочисленных типов и типов указателей это целое число, для символьных типов – строка из одного символа, для типов указателей на символы – строка Python или строка Unicode.16211622При получении атрибута `value` из экземпляра ctypes обычно каждый раз возвращается новый объект. [`ctypes`](https://python-all.ru/2.7/library/ctypes.html#module-ctypes) *не* реализует возврат исходного объекта, всегда создаётся новый объект. То же самое верно для всех остальных экземпляров объектов ctypes.16231624Фундаментальные типы данных при возврате в качестве результатов вызовов внешних функций или, например, при получении полей структуры или элементов массива прозрачно преобразуются в собственные типы Python. Другими словами, если внешняя функция имеет `restype` типа [`c_char_p`](https://python-all.ru/2.7/library/ctypes.html#ctypes.c_char_p), всегда будет возвращена строка Python, *а не* экземпляр [`c_char_p`](https://python-all.ru/2.7/library/ctypes.html#ctypes.c_char_p).16251626Подклассы фундаментальных типов данных *не* наследуют это поведение. Так что если `restype` внешней функции является подклассом [`c_void_p`](https://python-all.ru/2.7/library/ctypes.html#ctypes.c_void_p), вы получите экземпляр этого подкласса в результате вызова функции. Разумеется, вы можете получить значение указателя, обратившись к атрибуту `value`.16271628Вот фундаментальные типы данных ctypes:16291630#### `class ctypes.c_byte`16311632Представляет тип данных C `signed char` и интерпретирует значение как небольшое целое число. Конструктор принимает необязательный целочисленный инициализатор; проверка переполнения не выполняется.16331634#### `class ctypes.c_char`16351636Представляет тип данных C `char` и интерпретирует значение как одиночный символ. Конструктор принимает необязательный строковый инициализатор; длина строки должна быть ровно один символ.16371638#### `class ctypes.c_char_p`16391640Представляет тип данных C `char *`, когда он указывает на строку, завершающуюся нулевым символом. Для универсального указателя на символы, который может также указывать на двоичные данные, следует использовать `POINTER(c_char)`. Конструктор принимает целочисленный адрес или строку.16411642#### `class ctypes.c_double`16431644Представляет тип данных C `double`. Конструктор принимает необязательный инициализатор с плавающей запятой.16451646#### `class ctypes.c_longdouble`16471648Представляет тип данных C `long double`. Конструктор принимает необязательный инициализатор с плавающей запятой. На платформах, где `sizeof(long double) == sizeof(double)`, это псевдоним для [`c_double`](https://python-all.ru/2.7/library/ctypes.html#ctypes.c_double).16491650Новое в версии 2.6.16511652#### `class ctypes.c_float`16531654Представляет тип данных C `float`. Конструктор принимает необязательный инициализатор с плавающей запятой.16551656#### `class ctypes.c_int`16571658Представляет тип данных C `signed int`. Конструктор принимает необязательный целочисленный инициализатор; проверка переполнения не выполняется. На платформах, где `sizeof(int) == sizeof(long)`, это псевдоним для [`c_long`](https://python-all.ru/2.7/library/ctypes.html#ctypes.c_long).16591660#### `class ctypes.c_int8`16611662Представляет 8-битный тип данных C `signed int`. Обычно является псевдонимом для [`c_byte`](https://python-all.ru/2.7/library/ctypes.html#ctypes.c_byte).16631664#### `class ctypes.c_int16`16651666Представляет 16-битный тип данных C `signed int`. Обычно является псевдонимом для [`c_short`](https://python-all.ru/2.7/library/ctypes.html#ctypes.c_short).16671668#### `class ctypes.c_int32`16691670Представляет 32-битный тип данных C `signed int`. Обычно является псевдонимом для [`c_int`](https://python-all.ru/2.7/library/ctypes.html#ctypes.c_int).16711672#### `class ctypes.c_int64`16731674Представляет 64-битный тип данных C `signed int`. Обычно является псевдонимом для [`c_longlong`](https://python-all.ru/2.7/library/ctypes.html#ctypes.c_longlong).16751676#### `class ctypes.c_long`16771678Представляет тип данных C `signed long`. Конструктор принимает необязательный целочисленный инициализатор; проверка переполнения не выполняется.16791680#### `class ctypes.c_longlong`16811682Представляет тип данных C `signed long long`. Конструктор принимает необязательный инициализатор целого числа; проверка переполнения не выполняется.16831684#### `class ctypes.c_short`16851686Представляет тип данных C `signed short`. Конструктор принимает необязательный целочисленный инициализатор; проверка переполнения не выполняется.16871688#### `class ctypes.c_size_t`16891690Представляет тип данных C `size_t`.16911692#### `class ctypes.c_ssize_t`16931694Представляет тип данных C `ssize_t`.16951696Новое в версии 2.7.16971698#### `class ctypes.c_ubyte`16991700Представляет тип данных C `unsigned char`, интерпретирует значение как небольшое целое число. Конструктор принимает необязательный целочисленный инициализатор; проверка переполнения не выполняется.17011702#### `class ctypes.c_uint`17031704Представляет тип данных C `unsigned int`. Конструктор принимает необязательный целочисленный инициализатор; проверка переполнения не выполняется. На платформах, где `sizeof(int) == sizeof(long)`, это псевдоним для [`c_ulong`](https://python-all.ru/2.7/library/ctypes.html#ctypes.c_ulong).17051706#### `class ctypes.c_uint8`17071708Представляет 8-битный тип данных C `unsigned int`. Обычно является псевдонимом для [`c_ubyte`](https://python-all.ru/2.7/library/ctypes.html#ctypes.c_ubyte).17091710#### `class ctypes.c_uint16`17111712Представляет 16-битный тип данных C `unsigned int`. Обычно является псевдонимом для [`c_ushort`](https://python-all.ru/2.7/library/ctypes.html#ctypes.c_ushort).17131714#### `class ctypes.c_uint32`17151716Представляет 32-битный тип данных C `unsigned int`. Обычно является псевдонимом для [`c_uint`](https://python-all.ru/2.7/library/ctypes.html#ctypes.c_uint).17171718#### `class ctypes.c_uint64`17191720Представляет 64-битный тип данных C `unsigned int`. Обычно является псевдонимом для [`c_ulonglong`](https://python-all.ru/2.7/library/ctypes.html#ctypes.c_ulonglong).17211722#### `class ctypes.c_ulong`17231724Представляет тип данных C `unsigned long`. Конструктор принимает необязательный целочисленный инициализатор; проверка переполнения не выполняется.17251726#### `class ctypes.c_ulonglong`17271728Представляет тип данных C `unsigned long long`. Конструктор принимает необязательный целочисленный инициализатор; проверка переполнения не выполняется.17291730#### `class ctypes.c_ushort`17311732Представляет тип данных C `unsigned short`. Конструктор принимает необязательный инициализатор целого числа; проверка переполнения не выполняется.17331734#### `class ctypes.c_void_p`17351736Представляет тип C `void *`. Значение представлено как целое число. Конструктор принимает необязательный инициализатор целого числа.17371738#### `class ctypes.c_wchar`17391740Представляет тип данных C `wchar_t` и интерпретирует значение как строку Unicode из одного символа. Конструктор принимает необязательный строковый инициализатор; длина строки должна быть ровно один символ.17411742#### `class ctypes.c_wchar_p`17431744Представляет тип данных C `wchar_t *`, который должен быть указателем на широкую строку, завершающуюся нулевым символом. Конструктор принимает целочисленный адрес или строку.17451746#### `class ctypes.c_bool`17471748Представляет тип данных C `bool` (точнее, `_Bool` из C99). Его значение может быть `True` или `False`, а конструктор принимает любой объект, имеющий значение истинности.17491750Новое в версии 2.6.17511752#### `class ctypes.HRESULT`17531754Только Windows: Представляет значение `HRESULT`, содержащее информацию об успехе или ошибке вызова функции или метода.17551756#### `class ctypes.py_object`17571758Представляет тип данных C [`PyObject *`](https://python-all.ru/2.7/c-api/structures.html#c.PyObject). Вызов без аргумента создаёт указатель `NULL` [`PyObject *`](https://python-all.ru/2.7/c-api/structures.html#c.PyObject).17591760Модуль `ctypes.wintypes` предоставляет и другие специфичные для Windows типы данных, например `HWND`, `WPARAM` или `DWORD`. Также определены некоторые полезные структуры, такие как `MSG` или `RECT`.17611762### 15.17.2.8. Структурированные типы данных17631764#### `class ctypes.Union(*args, **kw)`17651766Абстрактный базовый класс для объединений в собственном порядке байт.17671768#### `class ctypes.BigEndianStructure(*args, **kw)`17691770Абстрактный базовый класс для структур в *big endian* порядке байтов.17711772#### `class ctypes.LittleEndianStructure(*args, **kw)`17731774Абстрактный базовый класс для структур в *little endian* порядке байтов.17751776Структуры с нестандартным порядком байтов не могут содержать поля типа указателя или любые другие типы данных, содержащие поля типа указателя.17771778#### `class ctypes.Structure(*args, **kw)`17791780Абстрактный базовый класс для структур в *нативном* порядке байтов.17811782Конкретные типы структур и объединений должны создаваться путем наследования одного из этих типов и как минимум определять переменную класса [`_fields_`](https://python-all.ru/2.7/library/ctypes.html#ctypes.Structure._fields_). [`ctypes`](https://python-all.ru/2.7/library/ctypes.html#module-ctypes) создаст [дескриптор](https://python-all.ru/2.7/glossary.html#term-descriptor)ы, которые позволяют читать и записывать поля через прямой доступ к атрибутам. Это –17831784#### `_fields_`17851786Последовательность, определяющая поля структуры. Элементы должны быть 2-кортежами или 3-кортежами. Первый элемент – имя поля, второй элемент задает тип поля; это может быть любой тип данных ctypes.17871788Для полей целочисленного типа, таких как [`c_int`](https://python-all.ru/2.7/library/ctypes.html#ctypes.c_int), можно указать третий необязательный элемент. Он должен быть небольшим положительным целым числом, определяющим разрядность поля (битовую ширину).17891790Имена полей должны быть уникальными в пределах одной структуры или объединения. Это не проверяется, но при повторении имен доступно только одно поле.17911792Можно определить переменную класса [`_fields_`](https://python-all.ru/2.7/library/ctypes.html#ctypes.Structure._fields_) *после* оператора class, определяющего подкласс Structure; это позволяет создавать типы данных, которые прямо или косвенно ссылаются сами на себя:17931794```python1795class List(Structure):1796    pass1797List._fields_ = [("pnext", POINTER(List)),1798                 ...1799                ]1800```18011802Однако переменная класса [`_fields_`](https://python-all.ru/2.7/library/ctypes.html#ctypes.Structure._fields_) должна быть определена до того, как tип будет впервые использован (создается экземпляр, вызывается `sizeof()` для него и т.д.). Последующие присваивания переменной класса [`_fields_`](https://python-all.ru/2.7/library/ctypes.html#ctypes.Structure._fields_) будут вызывать AttributeError.18031804Можно определять под-подклассы структурных типов, они наследуют поля базового класса плюс [`_fields_`](https://python-all.ru/2.7/library/ctypes.html#ctypes.Structure._fields_), определённые в под-подклассе, если таковые есть.18051806#### `_pack_`18071808Необязательное небольшое целое число, позволяющее переопределить выравнивание полей структуры в экземпляре. [`_pack_`](https://python-all.ru/2.7/library/ctypes.html#ctypes.Structure._pack_) должен быть уже определён к моменту присваивания [`_fields_`](https://python-all.ru/2.7/library/ctypes.html#ctypes.Structure._fields_), иначе это не будет иметь эффекта.18091810#### `_anonymous_`18111812Необязательная последовательность, перечисляющая имена безымянных (анонимных) полей. [`_anonymous_`](https://python-all.ru/2.7/library/ctypes.html#ctypes.Structure._anonymous_) должен быть уже определён, когда присваивается [`_fields_`](https://python-all.ru/2.7/library/ctypes.html#ctypes.Structure._fields_), иначе это не будет иметь эффекта.18131814Поля, перечисленные в этой переменной, должны быть полями типа структуры или объединения. [`ctypes`](https://python-all.ru/2.7/library/ctypes.html#module-ctypes) создаст дескрипторы в типе структуры, которые позволяют напрямую обращаться к вложенным полям без необходимости создавать поле структуры или объединения.18151816Вот пример типа (Windows):18171818```python1819class _U(Union):1820    _fields_ = [("lptdesc", POINTER(TYPEDESC)),1821                ("lpadesc", POINTER(ARRAYDESC)),1822                ("hreftype", HREFTYPE)]18231824class TYPEDESC(Structure):1825    _anonymous_ = ("u",)1826    _fields_ = [("u", _U),1827                ("vt", VARTYPE)]1828```18291830Структура `TYPEDESC` описывает COM-тип данных, поле `vt` указывает, какое из полей объединения является действительным. Поскольку поле `u` определено как анонимное, теперь можно обращаться к членам напрямую через экземпляр TYPEDESC. `td.lptdesc` и `td.u.lptdesc` эквивалентны, но первый вариант быстрее, так как не требует создания временного экземпляра объединения:18311832```python1833td = TYPEDESC()1834td.vt = VT_PTR1835td.lptdesc = POINTER(some_type)1836td.u.lptdesc = POINTER(some_type)1837```18381839Можно определять под-подклассы структур, они наследуют поля базового класса. Если в определении подкласса есть отдельная переменная [`_fields_`](https://python-all.ru/2.7/library/ctypes.html#ctypes.Structure._fields_), то поля, указанные в ней, добавляются к полям базового класса.18401841Конструкторы структур и объединений принимают как позиционные, так и именованные аргументы. Позиционные аргументы используются для инициализации полей-членов в том же порядке, в котором они перечислены в [`_fields_`](https://python-all.ru/2.7/library/ctypes.html#ctypes.Structure._fields_). Именованные аргументы в конструкторе интерпретируются как присваивания атрибутов, поэтому они инициализируют [`_fields_`](https://python-all.ru/2.7/library/ctypes.html#ctypes.Structure._fields_) с тем же именем или создают новые атрибуты для имён, отсутствующих в [`_fields_`](https://python-all.ru/2.7/library/ctypes.html#ctypes.Structure._fields_).18421843### 15.17.2.9. Массивы и указатели18441845#### `class ctypes.Array(*args)`18461847Абстрактный базовый класс для массивов.18481849Рекомендуемый способ создания конкретных типов массивов – умножение любого [`ctypes`](https://python-all.ru/2.7/library/ctypes.html#module-ctypes) типа данных на положительное целое число. В качестве альтернативы можно создать подкласс этого типа и определить переменные класса [`_length_`](https://python-all.ru/2.7/library/ctypes.html#ctypes.Array._length_) и [`_type_`](https://python-all.ru/2.7/library/ctypes.html#ctypes.Array._type_). Элементы массива можно читать и записывать с помощью стандартного доступа по индексу и срезу; при чтении среза полученный объект *не* является [`Array`](https://python-all.ru/2.7/library/ctypes.html#ctypes.Array).18501851#### `_length_`18521853Положительное целое число, задающее количество элементов в массиве. Индексы вне диапазона приводят к [`IndexError`](https://python-all.ru/2.7/library/exceptions.html#exceptions.IndexError). Будет возвращено [`len()`](https://python-all.ru/2.7/library/functions.html#len).18541855#### `_type_`18561857Задаёт тип каждого элемента в массиве.18581859Конструкторы подклассов массивов принимают позиционные аргументы, используемые для инициализации элементов по порядку.18601861#### `class ctypes._Pointer`18621863Приватный абстрактный базовый класс для указателей.18641865Конкретные типы указателей создаются вызовом [`POINTER()`](https://python-all.ru/2.7/library/ctypes.html#ctypes.POINTER) с типом, на который будет указываться; это делается автоматически [`pointer()`](https://python-all.ru/2.7/library/ctypes.html#ctypes.pointer).18661867Если указатель указывает на массив, его элементы можно читать и записывать с помощью стандартных операций индексирования и срезов. Объекты-указатели не имеют размера, поэтому [`len()`](https://python-all.ru/2.7/library/functions.html#len) вызовет [`TypeError`](https://python-all.ru/2.7/library/exceptions.html#exceptions.TypeError). Отрицательные индексы будут читать из памяти *до* указателя (как в C), а индексы за пределами диапазона, скорее всего, приведут к сбою с нарушением доступа (если повезёт).18681869#### `_type_`18701871Задаёт тип, на который указывается.18721873#### `contents`18741875Возвращает объект, на который указывает указатель. Присваивание этому атрибуту изменяет указатель так, чтобы он указывал на присвоенный объект.1876