Python 区别于;“基本原则”;ctypes数据类型及其子类? 介绍

Python 区别于;“基本原则”;ctypes数据类型及其子类? 介绍,python,parameter-passing,ctypes,dllimport,Python,Parameter Passing,Ctypes,Dllimport,我正在开发一个代码生成器,它将围绕ctypes.cdll加载的函数生成函数。生成器将获取有关参数的ctypes和返回值的信息,并生成如下行为(在某种程度上,看起来是这样的): func=getattr(dll'UglyLongAndUselessCName') func.argtypes=[ctypes.c_uint32,ctypes.c_int8,ctypes.c_char\u p] func.restype=ctypes.c_int16 def nice_python_name(句柄:int

我正在开发一个代码生成器,它将围绕
ctypes.cdll
加载的函数生成函数。生成器将获取有关参数的
ctypes
和返回值的信息,并生成如下行为(在某种程度上,看起来是这样的):

func=getattr(dll'UglyLongAndUselessCName')
func.argtypes=[ctypes.c_uint32,ctypes.c_int8,ctypes.c_char\u p]
func.restype=ctypes.c_int16
def nice_python_name(句柄:int,arg1:int,arg2:str)->int:
返回函数(句柄,arg1,arg2)
请注意python类型注释如何很好地处理函数参数的
ctypes
数据类型。还请注意,
nice\u python\u name
函数和
func
函数中的python类型之间没有转换代码。这就是我的问题

接近问题
ctypes
文档说,如果加载的DLL函数的
argtypes
属性是使用“基本数据类型”指定的,那么在调用加载的DLL函数时,
ctypes
将为您转换为python类型。这很好,因为在本例中,生成的代码与上面的示例类似-对于返回的值,我不需要显式地将
ctypes
对象转换为python类型的值,对于参数,则不需要显式地将其转换为python类型的值

然而,文档还说,对于“基本数据类型的子类”,这个技巧将不起作用,调用加载的DLL函数将需要
ctypes
对象作为参数,结果将是
ctypes
对象

这是关于它的摘录:

基本数据类型,当作为外部函数调用结果返回时,或例如通过检索结构字段成员或数组项返回时,将透明地转换为本机Python类型。换句话说,如果一个外部函数的
restype
c\u char\p
,那么您将始终收到一个Python字节对象,而不是
c\u char\p
实例

基本数据类型的子类不继承此行为。因此,如果一个外部函数
restype
c\u void\u p
的子类,那么您将从函数调用中收到该子类的一个实例。当然,您可以通过访问value属性来获取指针的值

所以,我想绕开这件事

似乎我需要知道类型是“基本”还是“子类”。这将帮助我定义代码生成的方式,即对于“基本”类型,生成的代码看起来与上面的示例类似,对于“基本”类型的子类,它将有额外的转换,从
ctypes
对象转换为合理的python类型(或者生成器只会抛出一个异常:“这不受支持”)

问题: 如何区分“基本
ctypes
数据类型”和“基本
ctypes
数据类型的子类”? 我查看了
ctypes
python模块的代码,发现
c\u void\u p
c\u char\u p
都是
ctypes的子类。\u SimpleCData
,因此一个在任何方面都不是另一个的子类

另外,我是否误解了这个问题也适用于输入参数,或者这只是返回值的处理

…我是否误解了这个问题也适用于输入参数,或者这只是返回值的处理

它不适用于输入参数,如下所示:

>>> dll=CDLL('msvcrt')
>>> dll.printf.argtypes = c_char_p,
>>> dll.printf(b'abc') # Note: 3 is the return value of printf
abc3
>>> class LPCSTR(c_char_p): # define a subtype
...  pass
...
>>> dll.printf.argtypes = LPCSTR,
>>> dll.printf(b'abc')
abc3
转换仍然适用于输入子类型;但是,输出子类型的工作方式不同,正如您的文档报价所述:

>>> dll.ctime.argtypes = c_void_p,
>>> dll.ctime.restype = c_char_p
>>> dll.ctime(byref(c_int(5)))
b'Wed Dec 31 16:00:05 1969\n'
>>> dll.ctime.restype = LPCSTR
>>> dll.ctime(byref(c_int(5))) # not converted to Python byte string
LPCSTR(1989707373328)
>>> x = dll.ctime(byref(c_int(5))) # but can get the value
>>> x.value
b'Wed Dec 31 16:00:05 1969\n'