Некоторые shared C-библиотеки не только экспортируют функции, но и экспортируют переменные. Примером такой переменной в библиотеке Python является Py_OptimizeFlag
- это целое число, равное 0, 1 или 2, в зависимости от флага -O
или -OO
, установленного при запуске.
Модуль ctypes
может получить доступ к таким значениям с помощью методов класса типа .in_dll()
, например ctypes.c_int.in_dll()
. В примере ниже pythonapi
- это предопределенный символьный тип, предоставляющий доступ к API Python C:
>>> opt_flag = c_int.in_dll(pythonapi, "Py_OptimizeFlag") >>> print(opt_flag) c_long(0)
Если бы интерпретатор был запущен с флагом -O
, то пример напечатал бы c_long(1)
или если бы был указан флаг -OO
, то c_long (2)
.
Смотрим расширенный пример обращения к указателю PyImport_FrozenModules
, экспортированному Python.
Цитата из документации к указателю PyImport_FrozenModules
:
Этот указатель инициализируется для указания на массив записей
struct _frozen
, завершающийся одним из элементов, все члены которого равныNULL
или нулю. При импорте модуляfrozen
(1) его поиск выполняется в этой таблице. Сторонним кодом можно получить динамически создаваемую коллекцию модулейfrozen
.
Так что манипулирование этим указателем может даже оказаться полезным. Чтобы ограничить размер примера, покажем только, как эту таблицу можно читать с помощью ctypes
:
>>> from ctypes import * >>> class struct_frozen(Structure): ... _fields_ = [("name", c_char_p), ... ("code", POINTER(c_ubyte)), ... ("size", c_int)] ...
Здесь определили тип данных struct _frozen
, поэтому можем получить указатель на таблицу:
>>> FrozenTable = POINTER(struct_frozen) >>> table = FrozenTable.in_dll(pythonapi, "PyImport_FrozenModules")
Поскольку table
является указателем на массив записей struct_frozen
, то можно перебирать его, но нам просто нужно убедиться, что цикл завершился, потому что указатели не имеют размера. Рано или поздно цикл, выйдет из строя из-за нарушения прав доступа или чего-то еще, поэтому лучше выйти из цикла, когда попадется запись с NULL
:
>>> for item in table: ... if item.name is None: ... break ... print(item.name.decode("ascii"), item.size) ... _frozen_importlib 31764 _frozen_importlib_external 41499 __hello__ 161 __phello__ -161 __phello__.spam 161
(1) Тот факт, что стандартный Python имеет модуль frozen
и пакет frozen
(обозначается отрицательным элементом size
), малоизвестен, он используется только для тестирования. Попробуйте, например, import __hello__
.
>>> import __hello__ # Hello world!