attrs带非平凡构造函数的frozen data class如何正确初始化
问题背景
- 需求为定义带非平凡(non-trivial)构造函数的frozen attrs数据类:构造函数需要在初始化数据成员前,先对输入参数做调整处理,初始编写的代码运行时会触发冻结实例不可修改的错误,初始代码如下:
from attrs import frozen @frozen(init=False) class Person: name: str def __init__(self, raw_name: str) -> None: if ":" in raw_name: self.name = raw_name[raw_name.find(":") + 1:] else: self.name = raw_name p = Person("Oren:IshShalom")
- 根据attrs官方文档说明:
如果类被标记为frozen(冻结)状态,无法在attrs_post_init或自定义编写的**init**方法中修改self属性,可通过使用
object.__setattr__(self, "attribute_name", value)的方式绕过该限制。
但该方案缺少具体实现示例,无法直接落地。
具体实现
把自定义初始化方法中所有直接给self属性赋值的语句,替换为object.__setattr__调用即可,修改后可正常运行的代码如下:
from attrs import frozen @frozen(init=False) class Person: name: str def __init__(self, raw_name: str) -> None: # 先完成输入参数的预处理逻辑 if ":" in raw_name: processed_name = raw_name[raw_name.find(":") + 1:] else: processed_name = raw_name # 绕过frozen拦截完成属性赋值 object.__setattr__(self, "name", processed_name) # 功能验证 p = Person("Oren:IshShalom") print(p.name) # 输出: IshShalom # 初始化完成后尝试修改属性会正常抛出FrozenInstanceError,符合不可变类的设计预期 # p.name = "new_name" # 取消注释运行会触发报错
实现原理
@frozen装饰器会重写类的__setattr__方法,拦截所有对实例属性的赋值操作,直接抛出不可修改的错误。直接调用根父类object原生的__setattr__方法,会跳过attrs添加的拦截逻辑,仅在初始化阶段完成属性赋值,不会破坏实例初始化完成后的不可变特性。
注意:该方式仅可用于初始化流程中(自定义
__init__、__attrs_post_init__),不要在初始化完成后的其他实例方法中使用,否则会违背frozen类设计的不可变约定。
内容的提问来源于stack exchange,提问作者OrenIshShalom
相关产品推荐
相关产品推荐

