Python3.12继承struct.Struct报错,Python3.11运行正常
Python 3.12中继承struct.Struct报错的原因及解决方法
问题根源
Python 3.12对struct.Struct的实现做了关键变更:它现在是不可变类型,实例化时__new__方法会直接验证传入的参数类型,要求必须是字符串或字节串。你的子类MyStruct仅重写了__init__,未重写__new__——实例化时父类的__new__会先收到你传入的字典参数,直接抛出类型错误,根本没等到子类__init__中调用super().__init__(fmt)的环节。
在Python 3.11及更早版本中,struct.Struct的参数检查仅在__init__中执行,子类重写__init__后可以先处理参数再调用父类方法,因此不会触发该错误。
解决方案
方案1:重写__new__方法适配不可变类型
由于不可变类型的实例创建由__new__负责,需要在该方法中先生成正确的格式字符串,再传给父类的__new__:
import struct class MyStruct(struct.Struct): format_chars = { "char": "c", "uint8_t": "B", "uint16_t": "H", "float": "f", "uint32_t": "I", } def __new__(cls, structure: dict[str, str]): fmt = cls._get_fmt_str(structure) return super().__new__(cls, fmt) @classmethod def _get_fmt_str(cls, structure: dict[str, str]) -> str: fmt = "".join( cls.format_chars.get(v, v) for v in structure.values() ) return f"<{fmt}" def __init__(self, structure: dict[str, str]): self.structure = structure # 父类__init__无需再调用,不可变类型的初始化已由__new__完成 if __name__ == "__main__": structure = {"uint8_t": "B"} my_struct = MyStruct(structure) assert my_struct.size == 1, "sizes not equal"
方案2:使用组合而非继承(更推荐)
放弃继承struct.Struct,改为在类内部维护一个struct.Struct实例,通过代理方法对外暴露功能,这样完全不受父类实现变更的影响:
import struct class MyStruct: format_chars = { "char": "c", "uint8_t": "B", "uint16_t": "H", "float": "f", "uint32_t": "I", } def __init__(self, structure: dict[str, str]): self.structure = structure fmt = self._get_fmt_str() self._struct = struct.Struct(fmt) def _get_fmt_str(self) -> str: fmt = "".join( self.format_chars.get(v, v) for v in self.structure.values() ) return f"<{fmt}" # 代理struct.Struct的属性和方法 @property def size(self): return self._struct.size def pack(self, *args): return self._struct.pack(*args) def unpack(self, buffer): return self._struct.unpack(buffer) if __name__ == "__main__": structure = {"uint8_t": "B"} my_struct = MyStruct(structure) assert my_struct.size == 1, "sizes not equal"
内容的提问来源于stack exchange,提问作者Phil B
相关产品推荐
相关产品推荐

