为何属性存在时hasattr仍抛出ValueError异常?
解析ctypes中NULL指针的hasattr与dir()行为差异
这确实是个挺有意思的ctypes“坑”,我来帮你理清楚背后的逻辑:
首先看你的代码示例:
>>> class demo(ctypes.Structure): ... _fields_ = [('data', ctypes.POINTER(ctypes.c_int16))] >>> b = demo() >>> b.data <__main__.LP_c_short object at 0x7f709c0550d0> >>> hasattr(b.data, 'contents') Traceback (most recent call last): File "<stdin>", line 1, in <module> ValueError: NULL pointer access NULL pointer access >>> 'contents' in dir(b.data) True
核心原因
ctypes里的指针对象(比如这里的LP_c_short)的contents属性是动态计算的属性,不是类里预先存好的静态属性:
dir()函数只会返回该指针类定义中声明的属性名称列表,不管当前指针是否有效(是否为NULL),所以'contents'会出现在结果里。- 而
hasattr()在检查属性时,会实际尝试去获取这个属性的值——对于contents来说,这意味着要解引用指针。如果指针是NULL(就像你这里的b.data,结构体实例化后指针默认未初始化,是NULL),解引用操作就会触发ValueError: NULL pointer access。
解决思路
如果你需要检查指针是否有可访问的contents,正确的做法是先判断指针本身是否非空:
if b.data: # ctypes指针在布尔上下文里,NULL会被视为False print(hasattr(b.data, 'contents')) # 这里不会报错,会返回True else: print("指针是NULL,无法访问contents")
本质上,contents属性的存在是确定的(从类定义层面),但只有当指针非空时,你才能安全地访问它——hasattr在这里的报错并不是因为属性不存在,而是访问属性时触发了指针解引用的错误。
内容的提问来源于stack exchange,提问作者s-m-e
相关产品推荐
相关产品推荐

