You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 19:55:42