如何为继承类实现__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
相关产品推荐
相关产品推荐

