基于ctypes封装面向对象C API的类型校验及冗余代码简化问题
面向对象C API的Python3封装冗余优化问题
我正尝试将一个极简的面向对象C API封装为Python3可用的接口,整体遵循的模式与以下方案一致:
当前C API定义
$ cat api.h /* ns::a */ typedef struct ns_a ns_a; ns_a* ns_a_create(); void ns_a_delete(ns_a* a); bool ns_a_execute(ns_a* a); /* ns::b */ typedef struct ns_b ns_b; ns_b* ns_b_create(); void ns_b_delete(ns_b* b); bool ns_b_run(ns_b* b);
现有封装实现
类型安全句柄定义
class _TypeSafeHandle: def __init__(self, ptr): self._as_parameter_ = ptr @classmethod def from_param(cls, obj): if obj.__class__ != cls: raise ValueError(f"Not a {obj.__class__.__name__} reference") if not obj._as_parameter_: raise ValueError("Passing undefined instance") return obj @final class _A(_TypeSafeHandle): """ 供库开发者使用,不计划对外公开 """ def __init__(self, ptr): super().__init__(ptr) @final class _B(_TypeSafeHandle): def __init__(self, ptr): super().__init__(ptr)
C API绑定代码
# a ns_a_create = _func('ns_a_create', c_void_p, None, _check_ns_a) ns_a_delete = _func('ns_a_delete', None, [_A]) ns_a_execute = _func('ns_a_execute', c_bool, [_A]) # b ns_b_create = _func('ns_b_create', c_void_p, None, _check_ns_b) ns_b_delete = _func('ns_b_delete', None, [_B]) ns_b_run = _func('ns_b_run', c_bool, [_B])
工具函数定义
def _func(name, restype, argtypes, errcheck): func = getattr(_lib, name) func.restype = restype func.argtypes = argtypes func.errcheck = errcheck return func
返回值校验函数
def _check_ns_a(result, _func, _args): if result is None: raise MemoryError("internal memory allocation failure") if type(result) != int: raise TypeError("Expecting int value for pointer") return _A(c_void_p(result)) def _check_ns_b(result, _func, _args): if result is None: raise MemoryError("internal memory allocation failure") if type(result) != int: raise TypeError("Expecting int value for pointer") return _B(c_void_p(result))
对外暴露的用户类
class A: def __init__(self): self._a = ns_a_create() def __enter__(self): return self def __exit__(self, exc_type, exc_val, exc_tb): ns_a_delete(self._a) def execute(self): ret = ns_a_execute(self._a) if not ret: raise ValueError("Could not execute")
现有实现说明
我希望保留_A、_B作为库内部实现细节,避免出现给错误的delete函数传入错误实例的问题,同时也认为该写法比类前置声明的写法可读性更高:
class A: # 前置声明 pass # _func声明中使用A代替_A作为参数类型 class A: # 实际实现
问题
有没有方法可以减少_A和_B之间的代码冗余?有没有方法可以减少_check_ns_a和_check_ns_b之间的代码冗余?
优化方案
1. 消除内部句柄类(_A/_B)的冗余
通过泛型工厂函数动态生成_TypeSafeHandle的子类,无需为每个类型单独写类定义:
from typing import Type def _create_handle_class(name: str) -> Type[_TypeSafeHandle]: @final class _Handle(_TypeSafeHandle): __doc__ = f"内部类型安全句柄类:{name}" def __init__(self, ptr): super().__init__(ptr) _Handle.__name__ = f"_{name}" return _Handle # 直接生成需要的内部类 _A = _create_handle_class("A") _B = _create_handle_class("B")
2. 消除校验函数的冗余
通过闭包生成对应类型的校验函数,无需为每个类型单独实现校验逻辑:
def _make_checker(handle_cls: Type[_TypeSafeHandle]): def _check(result, _func, _args): if result is None: raise MemoryError("internal memory allocation failure") if type(result) != int: raise TypeError("Expecting int value for pointer") return handle_cls(c_void_p(result)) return _check # 生成对应类型的校验函数 _check_ns_a = _make_checker(_A) _check_ns_b = _make_checker(_B)
后续新增其他C类型封装时,仅需要新增一行生成内部类、一行生成校验函数的代码即可,无需重复编写类定义和校验逻辑,冗余度大幅降低,同时保留了内部类类型安全、不暴露实现细节的要求。
内容的提问来源于stack exchange,提问作者malat
相关产品推荐
相关产品推荐

