Python中如何在DomainA与ServiceA类间拷贝属性?求复用方案
跨类实例属性互拷贝的第三方库推荐
我需要实现ServiceA类与DomainA类实例之间的属性值互拷贝,目前自己写的Convertor类方案不够灵活、复用性差,想找现成可用的第三方库/模块。注意:需求不是同一类不同实例的深浅拷贝。
当前实现代码:
class ServiceA(object): def __init__(self, api_name=None, author=None, region=None): self.api_name = api_name self.author = author self.region = region class DomainA(models.Model): api_name = models.CharField(max_length=512, blank=True, null=True) author = models.CharField(max_length=256, blank=True, null=True) region = models.CharField(max_length=256, blank=True, null=True) # 自己实现的转换类 class Convertor: def __init__(self): super(Convertor, self).__init__() def BoToDo(self, bo: ServiceA) -> DomainA: do = DomainA() if bo.api_name is not None: do.api_name = bo.api_name if bo.author is not None: do.author = bo.author if bo.region is not None: do.region = bo.region return do def DoToBo(self, do: DomainA) -> ServiceA: pass
推荐的第三方库方案:
1. cattrs(配合attrs)
cattrs是专门处理Python对象转换的工具,对普通类和attrs装饰的类都支持,能自动匹配同名属性,也支持自定义映射规则。
安装:
pip install attrs cattrs
用法示例:
from cattrs import structure, unstructure # ServiceA 转 DomainA def bo_to_do(bo: ServiceA) -> DomainA: bo_dict = unstructure(bo) return structure(bo_dict, DomainA) # DomainA 转 ServiceA def do_to_bo(do: DomainA) -> ServiceA: do_dict = unstructure(do) return structure(do_dict, ServiceA)
如果存在属性名不一致的情况,还可以注册自定义转换器,灵活性拉满。
2. pydantic
pydantic主打数据验证,但也能便捷实现跨类属性拷贝,支持字段重命名、默认值处理等场景。
安装:
pip install pydantic
用法示例:
from pydantic import BaseModel # 定义中间层Schema(也可直接用现有类转换) class CommonSchema(BaseModel): api_name: str | None = None author: str | None = None region: str | None = None class Config: orm_mode = True # 支持从Django Model这类ORM模型读取数据 # ServiceA 转 DomainA def bo_to_do(bo: ServiceA) -> DomainA: schema = CommonSchema(**vars(bo)) return DomainA(**schema.dict(exclude_unset=True)) # DomainA 转 ServiceA def do_to_bo(do: DomainA) -> ServiceA: schema = CommonSchema.from_orm(do) return ServiceA(**schema.dict(exclude_unset=True))
exclude_unset参数会忽略未赋值的属性,和你原来的if判断逻辑完全一致。
3. mapper
这是一个轻量对象映射库,支持显式定义字段映射规则,适合需要精细控制转换逻辑的场景。
安装:
pip install mapper
用法示例:
from mapper import Mapper # 创建映射器,同名属性可省略映射规则 mapper = Mapper() mapper.add_mapping(ServiceA, DomainA) mapper.add_mapping(DomainA, ServiceA) # ServiceA 转 DomainA def bo_to_do(bo: ServiceA) -> DomainA: return mapper.map(bo, DomainA) # DomainA 转 ServiceA def do_to_bo(do: DomainA) -> ServiceA: return mapper.map(do, ServiceA)
如果有属性名不同的情况,直接在add_mapping里传入{"源字段名": "目标字段名"}即可。
内容的提问来源于stack exchange,提问作者Jueyu
相关产品推荐
相关产品推荐

