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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 14:36:22