Python类中定义调用C DLL方法的正确方式及常见报错解决
问题原因逐一解析
1. 第一次修改报AttributeError的原因
你将func_1、func_2定义在了__init__方法内部,这两个属于函数内部的局部函数,只会在__init__执行时存在,不会成为类的实例方法,外部通过实例对象自然访问不到。
2. 第二次修改输出None的原因
你修改后的func_1、func_2只完成了DLL方法的属性配置(设置argtype、restype),既没有实际调用DLL的方法,也没有写return返回结果,Python函数默认返回None,所以输出都是空值。
3. 参数定义语法错误的原因
Python函数的参数位置只能写形参名,不能直接写类型。如果要加类型标注,正确的写法是在形参名后加冒号标注类型:
def func_1(self, var1: ctypes.c_uint8, var2: ctypes.c_uint8):
但这里其实不需要额外标注,你给DLL方法设置的argtype会自动完成参数类型转换,只要传入的参数值符合类型要求即可。
正确实现方案
这里提供两种常用的实现方式,你可以根据需求选择:
方案1:初始化时一次性完成所有DLL方法配置(推荐,性能更高)
和你原始逻辑一致,只是拆分了配置逻辑,避免__init__代码冗余:
import ctypes class my_outer_class: def __init__(self, dll_path: str = r'C:\\Users\OneDrive\HelloWorld\HelloWorld\loc\Debug\HelloWorld.dll'): # 加载DLL self._dll = ctypes.WinDLL(dll_path) # 批量初始化DLL方法 self._init_dll_functions() def _init_dll_functions(self): """封装DLL方法的初始化逻辑,私有方法避免外部随意调用""" # 配置function_1 self.py_function_1 = self._dll.function_1 self.py_function_1.argtype = (ctypes.c_uint8, ctypes.c_uint8) self.py_function_1.restype = ctypes.c_int # 配置function_2 self.py_function_2 = self._dll.function_2 self.py_function_2.argtype = (ctypes.c_uint8, ctypes.c_uint8) self.py_function_2.restype = ctypes.c_int
调用方式和你原始版本完全一致:
import hello myapi = hello.my_outer_class() result = myapi.py_function_1(123, 123) print(result) # 输出1 result = myapi.py_function_2(123, 123) print(result) # 输出0
方案2:调用时懒加载配置(适合DLL方法非常多的场景)
如果你的DLL有几十上百个方法,不需要每次初始化都全部配置,可以用懒加载的方式,第一次调用时才完成配置:
import ctypes class my_outer_class: def __init__(self, dll_path: str = r'C:\\Users\OneDrive\HelloWorld\HelloWorld\loc\Debug\HelloWorld.dll'): self._dll = ctypes.WinDLL(dll_path) self._py_function_1 = None self._py_function_2 = None def func_1(self, var1: int, var2: int) -> int: # 第一次调用时初始化 if not self._py_function_1: self._py_function_1 = self._dll.function_1 self._py_function_1.argtype = (ctypes.c_uint8, ctypes.c_uint8) self._py_function_1.restype = ctypes.c_int # 调用DLL方法并返回结果 return self._py_function_1(var1, var2) def func_2(self, var1: int, var2: int) -> int: if not self._py_function_2: self._py_function_2 = self._dll.function_2 self._py_function_2.argtype = (ctypes.c_uint8, ctypes.c_uint8) self._py_function_2.restype = ctypes.c_int return self._py_function_2(var1, var2)
调用方式和你修改后的测试代码一致:
import hello myapi = hello.my_outer_class() result = myapi.func_1(123, 123) print(result) # 输出1 result = myapi.func_2(123, 123) print(result) # 输出0
最佳实践建议
- DLL路径尽量用原始字符串(前缀加r),避免转义字符出错
- DLL方法的
argtype和restype只需要配置一次即可,不需要每次调用都重复配置 - 私有方法/属性加下划线前缀,和对外暴露的公共方法区分开
内容的提问来源于stack exchange,提问作者pekoms
相关产品推荐
相关产品推荐

