首页 > 解决方案 > 在运行时动态创建 CFUNCTYPE

问题描述

在 Python 中使用 ctypes 时,是否可以创建具有特定签名的 CFUNCTYPE,例如

ctypes.CFUNCTYPE (ctypes.c_void_p, ctypes.c_char_p)

动态而不是在运行时硬编码?在 Windows 上使用 Python 3.7

我目前拥有的代码创建字符串,例如“ctypes.CFUNCTYPE (ctypes.c_void_p, ctypes.c_char_p)”然后使用 eval 来创建对象。

我希望能够构造一个 CFUNCTYPE 对象而不必使用 eval。动态执行它的重点是我不知道 CFUNCTYPe 的签名,除非运行时。

标签: python-3.xctypes

解决方案


这是一个可能的示例,它ctypes.CFUNCTYPE从字符串返回 a 的实例:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import ctypes
import re


re_cfunc = re.compile(r"ctypes\.CFUNCTYPE\((.+)\)")

def functype_str_parser(functype_str: str):
    match = re_cfunc.match(functype_str)
    if not match:
        return None

    types_str = match.group(1)  # e.g. "ctypes.c_void_p, ctypes.c_char_p"
    argtypes = list()
    restype = None
    for i, type_str in enumerate(types_str.split(",")):
        module, ctypes_type_str = type_str.split(".")  # e.g. ["ctypes", "c_void_p"]
        ctype_type = getattr(ctypes, ctypes_type_str)  # e.g. <class 'ctypes.c_void_p'>
        if i == 0:
            # the first one is the return type of the CFUNCTYPE
            restype = ctype_type
        else:
            argtypes.append(ctype_type)

    return ctypes.CFUNCTYPE(restype, *argtypes)

if __name__ == '__main__':
    s = "ctypes.CFUNCTYPE(ctypes.c_void_p, ctypes.c_char_p)"
    print(f"Input: {s}")
    cfunc_type = functype_str_parser(s)
    if cfunc_type is None:
        # the string couldn't be parsed
        exit(-1)
    print(f"result: '{cfunc_type}'; type: {type(cfunc_type)}")

    # these are protected attributes and should not be used; the following code demonstrates the parsing was correct.
    print(f"restype: {cfunc_type._restype_}")
    for i, argtype in enumerate(cfunc_type._argtypes_):
        print(f"Argtype #{i}: {cfunc_type._argtypes_[i]}")

输出:

Input: ctypes.CFUNCTYPE(ctypes.c_void_p, ctypes.c_char_p)
result: '<class 'ctypes.CFUNCTYPE.<locals>.CFunctionType'>'; type: <class '_ctypes.PyCFuncPtrType'>
restype: <class 'ctypes.c_void_p'>
Argtype #0: <class 'ctypes.c_char_p'>

推荐阅读