如何用非None值的attrs类实例覆盖另一个同类型实例
合并attrs类实例并跳过None值的简洁方案
需求说明
需要合并同一个attrs类的多个实例,用后续实例的非None值覆盖前面实例的对应属性,实现先定义默认值、再按需覆盖的效果。预期效果如下:
from attr import attrs @attrs(auto_attribs=True) class A: a: int = None b: int = None instance_1 = A(a=1, b=2) instance_2 = A(b=3) # 预期结果:A(a=1, b=3) instance_3 = merge_instances(instance_1, instance_2)
现有方案优化
你当前的方案可行,但可以通过更简洁、规范的方式实现,以下是几种改进方案:
方案1:用字典推导式简化循环逻辑
直接用字典推导式替代手动循环,代码更紧凑:
from attr import attrs @attrs(auto_attribs=True) class A: a: int = None b: int = None def merge_instances(instance_1, instance_2): merged = { key: instance_2.__dict__[key] if instance_2.__dict__[key] is not None else instance_1.__dict__[key] for key in instance_1.__dict__ } return A(**merged) if __name__ == '__main__': instance_1 = A(a=1, b=2) instance_2 = A(b=3) instance_3 = merge_instances(instance_1, instance_2) print(instance_3) # 输出:A(a=1, b=3)
方案2:使用attrs官方asdict方法(更规范)
避免直接访问__dict__,改用attrs提供的asdict方法获取实例属性字典,更符合官方规范,也能兼容attrs的一些高级配置(比如field的别名):
from attr import attrs, asdict @attrs(auto_attribs=True) class A: a: int = None b: int = None def merge_instances(instance_1, instance_2): dict1 = asdict(instance_1) dict2 = asdict(instance_2) merged = {k: dict2[k] if dict2[k] is not None else v for k, v in dict1.items()} return A(**merged)
方案3:支持多实例合并的通用版本
如果需要合并多个实例(从左到右依次覆盖),可以写一个更通用的版本:
from attr import attrs, asdict @attrs(auto_attribs=True) class A: a: int = None b: int = None def merge_instances(*instances): if not instances: raise ValueError("至少需要传入一个实例") # 以第一个实例的属性为基础 merged_dict = asdict(instances[0]) # 依次用后续实例的非None值覆盖 for inst in instances[1:]: current_dict = asdict(inst) merged_dict.update({k: v for k, v in current_dict.items() if v is not None}) # 返回同类型的新实例 return type(instances[0])(**merged_dict) if __name__ == '__main__': instance_1 = A(a=1, b=2) instance_2 = A(b=3) instance_3 = merge_instances(instance_1, instance_2) print(instance_3) # A(a=1, b=3) # 测试多实例合并 instance_4 = A(a=4) instance_5 = merge_instances(instance_1, instance_2, instance_4) print(instance_5) # A(a=4, b=3)
方案优势
- 字典推导式让代码更简洁,可读性更强
- 使用
asdict比直接操作__dict__更安全,适配attrs的内部实现变化 - 多实例版本扩展性更好,能应对更复杂的覆盖场景
内容的提问来源于stack exchange,提问作者Guy
相关产品推荐
相关产品推荐

