Python ctypes Windows平台c_int32跨平台行为异常报错修复
问题现象
执行如下测试代码:
import ctypes print(ctypes.c_int32)
- Linux(及macOS)平台执行返回
<class 'ctypes.c_int32'> - Windows平台执行返回
<class 'ctypes.c_long'>
两个平台行为存在差异,目标是实现Windows端运行逻辑与Linux端完全一致。
问题排查记录
现有自定义类型实现
项目中定义了如下自定义ctype类:
class ctype: .... ctype.int32 = _make_ctype_from_ctypes(ctypes.c_int32) ....
配套的类型构造函数实现如下:
def _make_ctype_from_ctypes(ctypes_type): ctypes_namespace = dict(ctypes_type.__dict__) namespace = { "__module__": _Numeric.__module__, "_type_": ctypes_namespace["_type_"], } return type( ctypes_type.__name__.replace("c_", ""), tuple([_Numeric, *ctypes_type.__bases__]), namespace, )
报错触发点
报错触发位置为_Numeric类的__init__方法,箭头标注处为报错行:
class _Numeric: _type_: str def __init__(self, value): if isinstance(value, (bytearray, bytes)): value = struct.unpack(self._type_, value)[0] if isinstance(value, _Numeric): value = value.value if "int" in self.__class__.__name__: value = int(value) super().__init__(value) <-------------
初始报错堆栈信息如下:
Traceback (most recent call last): File "C:\Users\wotori\git\L2py\main.py", line 5, in <module> print(clock.ticks) File "C:\Users\wotori\git\L2py\game\game\models\world.py", line 40, in ticks return ctype.int(int(time.time() - self.start_time) / self.MSEC_IN_TICK) File "C:\Users\wotori\git\L2py\common\common\ctype.py", line 19, in __init__ super().__init__(value) TypeError: 'float' object cannot be interpreted as an integer
在报错行添加异常捕获逻辑打印参数,代码如下:
try: super().__init__(value) except Exception as e: print("error", e, value)
错误场景下的打印输出:
error 'float' object cannot be interpreted as an integer 1639347702.44 error 'float' object cannot be interpreted as an integer 0.0
- 该代码在Linux、macOS平台可正常运行,仅Windows平台触发上述错误。
最小复现示例
两台设备均安装64位版本Python,如下代码在Linux平台可无错运行,在Windows平台运行失败:
if __name__ == '__main__': from dataclasses import dataclass, field import time @dataclass(kw_only=True) class Clock: start_time: int = field(default=int(time.time())) _is_night = False TICKS_PER_SECOND = 10 MSEC_IN_TICK = 1000 / TICKS_PER_SECOND @property def is_night(self): return self.hours < 6 @property def hours(self): return (self.get_time() / 60) % 24 @property def ticks(self): return ctype.int(int(time.time() - self.start_time) / self.MSEC_IN_TICK) def get_time(self): return ctype.int32(self.ticks / (self.TICKS_PER_SECOND * 10)) import struct class _Numeric: _type_: str def __init__(self, value): if isinstance(value, (bytearray, bytes)): value = struct.unpack(self._type_, value)[0] if isinstance(value, _Numeric): value = value.value if "int" in self.__class__.__name__: value = int(value) super().__init__(value) def _make_ctype_from_ctypes(ctypes_type): ctypes_namespace = dict(ctypes_type.__dict__) namespace = { "__module__": _Numeric.__module__, "_type_": ctypes_namespace["_type_"], } return type( ctypes_type.__name__.replace("c_", ""), tuple([_Numeric, *ctypes_type.__bases__]), namespace, ) import ctypes class ctype: # noqa int = _make_ctype_from_ctypes(ctypes.c_int) int32 = _make_ctype_from_ctypes(ctypes.c_int32) clock = Clock() print(clock.ticks)
Windows平台报错堆栈:
Traceback (most recent call last): File "C:\Users\wotori\git\L2py\main.py", line 69, in <module> print(clock.ticks) File "C:\Users\wotori\git\L2py\main.py", line 23, in ticks return ctype.int(int(time.time() - self.start_time) / self.MSEC_IN_TICK) File "C:\Users\wotori\git\L2py\main.py", line 42, in __init__ super().__init__(value) TypeError: 'float' object cannot be interpreted as an integer
- 预期正常运行返回结果为
int(0)。
根因分析
问题核心是代码里两处逻辑依赖ctypes类型的__name__做判断,跨平台时别名差异导致逻辑失效:
- Windows
相关产品推荐
相关产品推荐

