py-automapper非常详细的详解——看完不会用你打我

一、py-automapper简介

开发过.Net项目的工程师大部分都用过AutoMapper来进行对象映射,py-automapper就是本第三方包的Python版本。我不太确定Python版本是否覆盖了.Net版本的所有功能,但常用功能都实现了:对象映射、空值处理、属性特殊处理等。

注意:本文章动笔时使用的py-automapper=v1.2.3

安装命令:pip install py-automapper

py-automapper Github地址、py-automapper pypi地址

二、简单类型映射(非继承自BaseModel)

两图对比,我们可以得出以下结论:

  • target_cls必须有__init__()且至少有一个参数,或target_cls必须继承自BaseModel(后面会解释原因)
  • source_cls可以有__init__()也可以没有(图1的PersonInfo有__init__()、图2的PersonInfo没有,图1图2的public_info01、public_info02都转换成功)
  • mapper.to(xxx).map()进行对象映射时不需要添加配置(public_info01、public_info02都转换成功)
  • mapper.map(xxx)进行对象映射时必须添加配置(图1的public_info03转换失败、图2添加配置后public_info03转换成功)
  • 图2只添加PersonInfo与PublicPersonInfo的配置即可转换成功,无需配置Address的映射关系,说明简单类型映射时只需要配置source_cls与target_cls,内部属性是类型我们不用再为其添加配置

三、dataclass的作用(非继承自BaseModel)

 本图跟上一张图片的区别有两点:本图的Address()添加了@dataclass标签,内部的__init__()换成了四个属性。最终结果相同说明@dataclass为Address添加了__init__()方法,后来我查了一下资料果然不出所料:@dataclass装饰器可以帮你生成 __repr__、 __init__、__str__ 等等方法,帮助我们简化数据类的定义过程。

四、复杂类型映射(继承自BaseModel)

两图对比,我们可以得出以下结论:

  • 内部属性是类型且直接或间接继承自BaseModel时,我们必须单独为内部属性的类型添加配置,不然会报错(后面会解释原因)
  • 直接或间接继承BaseModel也会像@dataclass一样帮你生成 __repr__、 __init__、__str__ 等等方法,帮助我们简化数据类的定义过程

五、fields_mapping自定义属性映射关系

 六、深度分析遗留问题1

问题1:target_cls必须有__init__()且至少有一个参数,或target_cls必须继承自BaseModel

def map(self, obj: object, *,
    skip_none_values: bool = False,
    fields_mapping: FieldsMap = None,
    use_deepcopy: bool = True,
) -> T:  # type: ignore [type-var]
    """Produces output object mapped from source object and custom arguments

    Args:
        obj (object): Source object to map to `target class`.
        skip_none_values (bool, optional): Skip None values when creating `target class` obj. Defaults to False.
        fields_mapping (FieldsMap, optional): Custom mapping.
            Specify dictionary in format {"field_name": value_object}. Defaults to None.
        use_deepcopy (bool, optional): Apply deepcopy to all child objects when copy from source to target object.
            Defaults to True.

    Raises:
        MappingError: No `target class` specified to be mapped into.
            Register mappings using `mapped.add(...)` or specify `target class` using `mapper.to(target_cls).map()`.
        CircularReferenceError: Circular references in `source class` object are not allowed yet.

    Returns:
        T: instance of `target class` with mapped values from `source class` or custom `fields_mapping` dictionary.
    """
    obj_type = type(obj)
    if obj_type not in self._mappings:
        raise MappingError(f"Missing mapping type for input type {obj_type}")
    obj_type_prefix = f"{obj_type.__name__}."

    target_cls, target_cls_field_mappings = self._mappings[obj_type]

    common_fields_mapping = fields_mapping
    if target_cls_field_mappings:
        # transform mapping if it's from source class field
        common_fields_mapping = {
            target_obj_field: getattr(obj, source_field[len(obj_type_prefix) :])
            if isinstance(source_field, str)
            and source_field.startswith(obj_type_prefix)
            else source_field
            for target_obj_field, source_field in target_cls_field_mappings.items()
        }
        if fields_mapping:
            common_fields_mapping = {
                **common_fields_mapping,
                **fields_mapping,
            }  # merge two dict into one, fields_mapping has priority

    return self._map_common(obj, target_cls, set(),
        skip_none_values=skip_none_values, custom_mapping=common_fields_mapping, use_deepcopy=use_deepcopy,
    )

对象映射的入口是map()方法,上面就是map()的源代码,map()最后调用了_map_common(),_map_common()又调用了_get_fields(),下面先分析_get_fields(),再说_map_common()。 

根据_get_fields()截图中控制台打印的内容可知:

  • self._class_specs中包含pydantic.main.BaseModel
  • self._classifier_specs包含__init_method_classifier__
  • classifier(target_cls)返回构造函数的参数

由此三点就解释了问题1的原因,【target_cls必须有__init__()且至少有一个参数】对应263~265行,【target_cls必须继承自BaseModel】对应259~261行,如果这两条都不满足的话直接raise MappingError,因此两条中至少要满足1条。

_get_fields()拿到target_cls的所有属性后,回到_map_common()循环从source_cls的对象中获取对应的属性值,最后cast()拿到target_cls的对象。

 七、深度分析遗留问题2

问题2:内部属性是类型且直接或间接继承自BaseModel时,我们必须单独为其添加配置,不然会报错 

经过调试发现不添加配置时_map_subobject()报错了,_map_common()截图的340行调用了_map_subobject(),即深度拷贝时获取PersonInfo.address的属性值报错了。

根据_map_subobject()截图中控制台打印的内容可知:

  • 当前obj是Address类型
  • 由于Address继承自BaseModel,导致obj.__iter__()被重写,_is_sequence(obj)判断为true
  • obj是Address类型不是dict,所以290行判断失败进入298行,但实际上Address是不能用[...]实参来创建对象的
  • 常见的可迭代对象:tuple、list、set,这些可以用一个[...]实参来创建对象(如图所示)

至此我们可以得出结论:内部属性是类型且直接或间接继承自BaseModel时,我们必须单独为其添加配置,不然会报错。我认为这不能算是问题,只能说是1.2.3版本中处理_is_sequence()时少判断了BaseModel子类这一种情况,作者如果后续能改进的话咱们用起来也会更方便。

 

这也是一篇干货满满的文章,都看到这里了希望大家能点赞、评论支持下,谢谢。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/801169.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

[米联客-安路飞龙DR1-FPSOC] FPGA基础篇连载-15 SPI接收程序设计

软件版本:Anlogic -TD5.9.1-DR1_ES1.1 操作系统:WIN10 64bit 硬件平台:适用安路(Anlogic)FPGA 实验平台:米联客-MLK-L1-CZ06-DR1M90G开发板 板卡获取平台:https://milianke.tmall.com/ 登录“米联客”FPGA社区 ht…

【漏洞复现】WordPress——Recall——SQL注入(CVE-2024-32709)

声明:本文档或演示材料仅供教育和教学目的使用,任何个人或组织使用本文档中的信息进行非法活动,均与本文档的作者或发布者无关。 文章目录 漏洞描述漏洞复现测试工具 漏洞描述 WordPress是一款免费开源的内容管理系统(CMS),最初是…

Java 反射用法和8道练习题

目录 一、什么是反射二、反射的核心接口和类三、测试代码 Bean 类和目录结构Person 类代码目录结构 四、获取 Class 对象五、获取构造方法 Constructor 并使用六、获取成员变量 Field 并使用七、获取成员方法 Method 并使用八、练习1. 使用反射获取String类的所有公有方法&…

虚拟机:VMware功能,安装与使用

目录 一、虚拟机介绍 二、VMware 1.介绍 2.安装 (1)根据提示按步骤安装​编辑 (2)更改软件的安装地址​编辑 (3)根据自己的需求选择是否需要软件更新​编辑 (4)根据需求选择…

3. JavaSE ——【逻辑运算符】

🚀 开场白 亲爱的读者,大家好!我是一名正在学习编程的高校生。在这个博客里,我将和大家一起探讨编程技巧、分享实用工具,并交流学习心得。希望通过我的博客,你能学到有用的知识,提高自己的技能&…

Billu_b0x靶机

信息收集 使用arp-scan 生成网络接口地址来查看ip 输入命令: arp-scan -l 可以查看到我们的目标ip为192.168.187.153 nmap扫描端口开放 输入命令: nmap -min-rate 10000 -p- 192.168.187.153 可以看到开放2个端口 nmap扫描端口信息 输入命令&…

【深度学习】PyTorch框架(2):激活函数

1.引言 在文中,我们将深入探讨流行的激活函数,并分析它们在神经网络优化特性中的作用。激活函数在深度学习模型中扮演着至关重要的角色,因为它们为网络引入了非线性特性。尽管文献中描述了众多的激活函数,但它们并非一视同仁&…

北京交通大学《深度学习》专业课,实验2-前馈神经网络

1. 源代码 见资源“北京交通大学《深度学习》专业课,实验2-前馈神经网络” 2. 实验内容 (1)手动实现前馈神经网络解决上述回归、二分类、多分类任务 分析实验结果并绘制训练集和测试集的loss曲线 (2)利用to…

发电机保护屏的工作原理和组成

发电机保护屏的工作原理和组成 发电机保护屏的工作原理是通过监测发电机的电气参数和运行状态,‌一旦发现异常或故障,‌及时采取相应的保护措施,‌以确保发电机的安全运行。‌ 发电机保护屏通常包含各种传感器、‌保护继电器和控制…

Golang | Leetcode Golang题解之第231题2的幂

题目&#xff1a; 题解&#xff1a; func isPowerOfTwo(n int) bool {const big 1 << 30return n > 0 && big%n 0 }

整数或小数点后补0操作

效果展示&#xff1a; 整数情况&#xff1a; 小数情况&#xff1a; 小编这里是以微信小程序举例&#xff0c;代码通用可兼容vue等。 1.在utils文件下创建工具util.js文本 util.js页面&#xff1a; // 格式…

docker desktop历史版本安装

1.安装choco Windows安装 choco包管理工具-CSDN博客 2.通过choco安装 下面例子为安装旧版2.3.0.2,其它版本类似 Chocolatey Software | Docker Desktop 2.3.0.2 https://download.docker.com/win/stable/45183/Docker%20Desktop%20Installer.exe choco install docker-des…

ESP32-S3多模态交互方案在线AI语音设备应用,启明云端乐鑫代理商

随着物联网&#xff08;IoT&#xff09;和人工智能&#xff08;AI&#xff09;技术的飞速发展&#xff0c;嵌入式设备正逐渐变得智能化&#xff0c;让我们的家庭生活变得更加智能化和个性化。 随着大型语言模型的不断进步和优化&#xff0c;AI语音机器人设备能够实现更加智能、…

绝缘子污秽comsol仿真参数

&#x1f3c6;本文收录于《CSDN问答解答》专栏&#xff0c;主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&收藏&…

Java+springboot+vue智慧班牌小程序源码,智慧班牌系统可以提供哪些服务?

智慧班牌全套源码&#xff0c;系统技术架构&#xff1a;Javaspringbootvue element-ui小程序电子班牌&#xff1a;Java Android演示正版授权。 智慧班牌在智慧校园的数字化建设中提供了多种服务&#xff0c;这些服务不仅丰富了校园的信息展示方式&#xff0c;还促进了家校互动…

渲染100农场有哪些优势?渲染100邀请码1a12

渲染100是知名的渲染农场&#xff0c;深受广大设计师欢迎&#xff0c;比起其他农场&#xff0c;它有什么优势呢&#xff1f;我们一起来看看。 1、资源丰富 渲染100拥有强大的计算集群&#xff0c;能多线处理大规模、超复杂的场景渲染需要&#xff0c;性能卓越。2、成本低廉 渲…

文件的顺序读写

文件读写函数介绍 文件顺序读写函数 函数名功能适用于fputc 字符输出函数 所有输出流 fgetc 字符输⼊函数 所有输⼊流 fputs ⽂本⾏输出函数 所有输出流fgets ⽂本⾏输⼊函数 所有输⼊流fprintf 格式化输出函数 所有输出流fscanf 格式化输⼊函数 所有输⼊流fwrite ⼆进制输出…

Multi-modal Information Fusion for Action Unit Detection in the Wild

标题&#xff1a;多模态信息融合用于野外动作单元检测 源文链接&#xff1a;https://openaccess.thecvf.com/content/CVPR2023W/ABAW/papers/Deng_Multi-Modal_Information_Fusion_for_Action_Unit_Detection_in_the_Wild_CVPRW_2023_paper.pdfhttps://openaccess.thecvf.com/…

【HarmonyOS开发】Tabs使用封装

背景 在写Tabs时&#xff0c;会使用很多个TabContent来实现不同页面的展示内容&#xff0c;但是如果TabContent数量很多时&#xff0c;会导致Tabs代码量大而且很臃肿&#xff0c;因此想着尝试去封装Tabs的使用&#xff0c;可以让界面整洁和对内容界面的解耦。 主要依托于wrap…

数据驱动下的私域运营战略布局

一、以用户为中心的组织重构或整合 发现&#xff0c;市场上大部分做的非常成功的私域项目&#xff0c;都是由CEO推动的、基于该战略的组织重构去驱动的。 我们也看到&#xff0c;在很多公司&#xff0c;私域运营是由品牌部门、CRM部门和Trade Marketing部门合作一起运营的。 …