Введение
Я работаю над генератором кода, который будет генерировать функции вокруг ctypes.cdll
загруженных функций.Генератор будет получать информацию о ctypes
аргументов и возвращаемого значения и генерировать что-то, что ведет себя (и, в некоторой степени, выглядит) следующим образом:
func = getattr(dll, 'UglyLongAndUselessCName')
func.argtypes = [ctypes.c_uint32, ctypes.c_int8, ctypes.c_char_p]
func.restype = ctypes.c_int16
def nice_python_name(handle: int, arg1: int, arg2: str) -> int:
return func(handle, arg1, arg2)
Обратите внимание, как играют аннотации типа Pythonхорошо с ctypes
типами данных аргументов функции.Также обратите внимание, что в функциях nice_python_name
и func
нет кода преобразования между типами python.Вот о чем мой вопрос.
Знакомство с проблемой
В документах ctypes
говорится, что если атрибут argtypes
загруженной функции DLL указан с использованием "основных типов данных"msgstr ", то при вызове загруженных функций DLL ctypes
выполнит преобразование в типы python.Это здорово, потому что в этом случае мой сгенерированный код будет выглядеть как в примере выше - мне не нужно явно преобразовывать ctypes
объекты в значения типа Python для возвращаемых значений и наоборот для аргументов.
Однако в документах также говорится, что для «подклассов основных типов данных» этот трюк не сработает, и вызов загруженной функции DLL потребует ctypes
объектов для аргументов, а в результате будет ctypes
объект.
Это выдержка из ctypes
документов об этом:
Основные типы данных, когда возвращаются как результаты вызова сторонней функции, или, например,путем извлечения членов поля структуры или элементов массива прозрачно преобразуются в собственные типы Python.Другими словами, если сторонняя функция имеет restype
из c_char_p
, вы всегда получите объект байтов Python, а не экземпляр c_char_p
.
Подклассы основных типов данных не наследуют это поведение,Итак, если сторонняя функция restype
является подклассом c_void_p
, вы получите экземпляр этого подкласса из вызова функции.Конечно, вы можете получить значение указателя, обратившись к атрибуту value.
Итак, я хотел бы обойти это.
Кажется, мне нужно знать,тип является "фундаментальным" или "подклассом".Это поможет мне определить способ генерации кода, то есть для «фундаментальных» типов сгенерированный код будет выглядеть аналогично приведенному выше примеру, а для «подклассов фундаментальных» типов он будет иметь дополнительное преобразование из ctypes
объектов в разумныетипы python (или генератор просто выдаст исключение, говорящее «это не поддерживается»).
Вопрос:
Как я могу различить «фундаментальные ctypes
типы данных» и «подклассы»фундаментальных ctypes
типов данных "?
Я изучил код модуля ctypes
python и обнаружил, что c_void_p
и c_char_p
являются подклассами ctypes._SimpleCData
, следовательно, один не является подклассомс другой стороны.
Кроме того, я неправильно понимаю, что эта проблема также относится к входным аргументам, или это только сделка для возвращаемых значений?