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

如何为继承类实现__post_init__方法?解决属性冻结继承问题

解决子类继承冻结类无法添加属性的问题

核心思路是将实例冻结的时机从父类__init__的末尾,延迟到一个可被子类重写的钩子方法(类似dataclass的__post_init__)中执行。这样子类可以先完成自身属性的初始化,再触发实例冻结。

修改后的父类Foo实现

class Foo:
    def __init__(self):
        self._is_frozen = False
        # 初始化父类自有属性
        self.parent_attr = "parent_default"
        # 调用钩子方法,默认会冻结实例
        self.__post_init__()

    def __setattr__(self, name, value):
        # 冻结状态下仅允许修改已存在的属性
        if self._is_frozen and name not in self.__dict__:
            raise AttributeError(f"无法为冻结实例添加新属性 '{name}'")
        super().__setattr__(name, value)

    def __post_init__(self):
        # 钩子方法:默认在这里完成实例冻结
        self._is_frozen = True

子类Bar的实现

子类只需重写__post_init__,先完成自身属性的赋值,再调用父类的钩子方法触发冻结:

class Bar(Foo):
    def __init__(self):
        super().__init__()

    def __post_init__(self):
        # 先初始化子类属性(此时实例未冻结,允许新增)
        self.child_attr = "child_default"
        # 调用父类的__post_init__完成冻结
        super().__post_init__()

测试验证

# 测试父类实例
foo = Foo()
foo.parent_attr = "updated_parent"  # 允许修改已有属性
try:
    foo.new_attr = "test"  # 新增属性会触发异常
except AttributeError as e:
    print(e)  # 输出:无法为冻结实例添加新属性 'new_attr'

# 测试子类实例
bar = Bar()
bar.child_attr = "updated_child"  # 允许修改子类属性
bar.parent_attr = "revised_parent"  # 允许修改父类属性
try:
    bar.new_child_attr = "test"  # 新增属性触发异常
except AttributeError as e:
    print(e)  # 输出:无法为冻结实例添加新属性 'new_child_attr'

关键说明

  • 父类把冻结逻辑从__init__移到__post_init__,给子类预留了初始化自有属性的窗口
  • 子类重写__post_init__时,必须在最后调用父类的同名方法,否则实例不会被冻结
  • 如果子类不需要额外初始化属性,无需重写__post_init__,会自动继承父类的冻结逻辑

内容的提问来源于stack exchange,提问作者y3t1

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 09:50:25