使用 RaiseExceptionMeta 元类隐式装饰 Validator 类中的所有校验方法

目录

  • 一、前置说明
    • 1、总体目录
    • 2、相关回顾
    • 3、本节目标
  • 二、操作步骤
    • 1、项目目录
    • 2、代码实现
    • 3、测试代码
    • 4、日志输出
  • 三、后置说明
    • 1、要点小结
    • 2、下节准备

一、前置说明

1、总体目录

  • 《 pyparamvalidate 参数校验器,从编码到发布全过程》

2、相关回顾

  • 使用 raise_exception 装饰器,优化校验方法

3、本节目标

  • 了解元类 metaclass 的使用。
  • 了解 __new__ 方法的使用。
  • 了解如何使用元类隐式装饰类中的所有方法。

二、操作步骤

1、项目目录

  • atme : @me 用于存放临时的代码片断或其它内容。
  • pyparamvalidate : 新建一个与项目名称同名的package,为了方便发布至 pypi
  • core : 用于存放核心代码。
  • tests : 用于存放测试代码。
  • utils : 用于存放一些工具类或方法。

2、代码实现

atme/demo/validator_v3/validator.py

import functools
import inspectdef _error_prompt(value, exception_msg=None, rule_des=None, field=None):"""优先使用校验方法中的错误提示, 如果方法中没有错误提示,则使用"字段规则描述"代替错误提示拼接出:name error: "123" is invalid. due to: name must be string."""default = f'"{value}" is invalid.'prompt = exception_msg or rule_desprompt = f'{default} due to: {prompt}' if prompt else defaultprompt = f'{field} error: {prompt}' if field else promptreturn promptdef raise_exception(func):@functools.wraps(func)def wrapper(self, *args, **kwargs):bound_args = inspect.signature(func).bind(self, *args, **kwargs).argumentsexception_msg = kwargs.get('exception_msg', None) or bound_args.get('exception_msg', None)error_prompt = _error_prompt(self.value, exception_msg, self._rule_des, self._field)result = func(self, *args, **kwargs)if not result:raise ValueError(error_prompt)return selfreturn wrapperclass RaiseExceptionMeta(type):def __new__(cls, name, bases, dct):for key, value in dct.items():# 如果是静态方法,则将它替换为一个新的静态方法,新的静态方法调用 raise_exception 函数,将原静态方法作为参数传递给raise_exceptionif isinstance(value, staticmethod):dct[key] = staticmethod(raise_exception(value.__func__))# 如果是类方法,则将它替换为一个新的类方法,新的类方法调用 raise_exception 函数,将原类方法作为参数传递给raise_exceptionif isinstance(value, classmethod):dct[key] = classmethod(raise_exception(value.__func__))# 如果是普通的成员方法,则将它替换为一个新的函数,新函数调用 raise_exception 函数,将原函数作为参数传递给 raise_exception# 排除掉以双下划线 __ 开头的方法, 如 __init__,__new__等if inspect.isfunction(value) and not key.startswith("__"):dct[key] = raise_exception(value)return super().__new__(cls, name, bases, dct)class Validator(metaclass=RaiseExceptionMeta):def __init__(self, value, field=None, rule_des=None):""":param value: 待校验的值:param field: 校验字段- 用于提示具体哪个字段错误- 如 'name error: name must be string'- error 前面的 `name` 即为 field:param rule_des: 校验规则描述"""self.value = valueself._field = fieldself._rule_des = rule_desdef is_string(self, exception_msg=None):return isinstance(self.value, str)def is_not_empty(self, exception_msg=None):return bool(self.value)

3、测试代码

atme/demo/validator_v3/test_validator.py

import pytestfrom atme.demo.validator_v3.validator import Validatordef test_validator_01():"""在 Validator 实例化时,不给 field、rule_des 传值; 在校验方法中,不给 exception_msg 传值"""validator = Validator('Jane')assert validator.is_string().is_not_empty()with pytest.raises(ValueError) as exc_info:validator = Validator(123)validator.is_string().is_not_empty()assert 'invalid' in str(exc_info.value)print(exc_info.value)  # 输出: "123" is invalid.def test_validator_02():"""在 Validator 实例化时,给 field、rule_des 传值"""validator = Validator('Jane', field='name', rule_des='name must be string from rule des.')assert validator.is_string().is_not_empty()with pytest.raises(ValueError) as exc_info:validator = Validator(123, field='name', rule_des='name must be string from rule des.')validator.is_string().is_not_empty()assert 'name must be string from rule des.' in str(exc_info.value)print(exc_info.value)  # 输出: name error: "123" is invalid. due to: name must be string from rule des.def test_validator_03():"""在 Validator 实例化时,给 field、rule_des 传值; 在校验方法中,给 exception_msg 传值"""validator = Validator('Jane', field='name', rule_des='name must be string from rule des.')assert validator.is_string().is_not_empty()with pytest.raises(ValueError) as exc_info:validator = Validator(123, field='name', rule_des='name must be string from rule des.')validator.is_string('name must be string from method exception msg.').is_not_empty()assert 'name must be string from method exception msg.' in str(exc_info.value)print(exc_info.value)  # 输出: "123" is invalid due to "name error: name must be string from method exception msg."def test_validator_04():"""field_name 为空"""validator = Validator('Jane', rule_des='name must be string from rule des.')assert validator.is_string().is_not_empty()with pytest.raises(ValueError) as exc_info:validator = Validator(123, rule_des='name must be string from rule des.')validator.is_string('name must be string from method exception msg.').is_not_empty()assert 'name must be string from method exception msg.' in str(exc_info.value)print(exc_info.value)  # 输出: "123" is invalid due to "name must be string from method exception msg."

4、日志输出

执行 test 的日志如下,验证通过:

============================= test session starts =============================
collecting ... collected 4 itemstest_validator.py::test_validator_01 PASSED                              [ 25%]"123" is invalid.test_validator.py::test_validator_02 PASSED                              [ 50%]name error: "123" is invalid. due to: name must be string from rule des.test_validator.py::test_validator_03 PASSED                              [ 75%]name error: "123" is invalid. due to: name must be string from method exception msg.test_validator.py::test_validator_04 PASSED                              [100%]"123" is invalid. due to: name must be string from method exception msg.============================== 4 passed in 0.01s ==============================

三、后置说明

1、要点小结

  • 元类 metaclass 可以控制类的创建过程,可以动态的修改类的属性、方法和其他行为,demo 示例如下:

class MyMeta(type):def __new__(cls, name, bases, dct):# 在创建类之前的操作print(f"Creating class: {name}")return super().__new__(cls, name, bases, dct)class MyClass(metaclass=MyMeta):pass# 输出:Creating class: MyClass
  • __new__ 方法用于修改类的行为,在 RaiseExceptionMeta 类中,它会遍历类的字典(包括属性和方法),并对其中的静态方法、类方法和普通成员方法进行修改。
  • __new__ 是在对象实例创建之前调用的方法,用于创建并返回一个新的实例;__init__ 是实例创建之后调用的方法,用于对实例进行初始化。
  • 经过优化后,由于校验方法没有 return self , 导致编辑器如 pycharm 不能智能识别可用的链式调用方法(如下图),对用户很不友好,可以继续优化。

2、下节准备

  • 使用 TypeVar 创建 Self 类变量,方便用户在 pycharm 编辑器中进行链式调用

点击返回主目录

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Qt QLineEdit文本框控件

文章目录 1 属性和方法1.1 占位字符串1.2 对齐方式1.3 回显模式1.4 读写控制1.5 格式控制1.6 信号和槽 2 实例2. 布局2.2 代码实现 QLineEdit 是Qt 中的文本框,准确地说是单行文本框,通常用于接受用户的输入。 比如用户输入用户名、密码等,都…

ChatGPT付费创作系统V2.5.5独立版+前端

ChatGPT付费创作系统V2.5.5版本优化了很多细节,功能增加增加长篇写作功能。该版本为编译版无开源,本版本特别处理了后台弹窗、暗链网址。特别优化了数据库。升级过程中未发现任何BUG,全新安装或者升级安装均未出现400或者500错误,…

【数据结构专题】「延时队列算法」史上手把手带你认识一下数据结构的基本概念与术语

在本节中,我们将对一些概念和术语赋以确定的含义,以便与读者取得“共同的语言”。这些概念和术语将在以后的章节中多次出现。 数据 概念 数据(data) 是对客观事物的符号表示, 在计算机科学中是指所有能输人到计算机中并被计算机程序处理的…

Python 工具 | conda 基本命令

Hi,大家好,我是源于花海。本文主要了解 Python 的工具的 conda 相关的基本命令。Conda 是一个开源的软件包管理系统和环境管理系统,用于安装多个版本的软件包及其依赖关系,并在它们之间轻松切换。在Windows下,需要安装…

Mobile Aloha 【软硬件原理+代码解析】

1. Mobile ALOHA Hardware2. Imitation Learning3. Co-training with Static ALOHA Data4. Task Setting5. Experiments5.1 ACT5.2 对比ACT、Diffusion Policy和VINN 6. Software Code Analyze Mobile ALOHA: 利用低成本全身远程操作系统学习复杂的双手移动操作技能 [译] 硬件代…

Elasticsearch基本操作之文档操作

本文来说下Elasticsearch基本操作之文档操作 文章目录 文档概述创建文档示例创建文档(生成随机id)创建文档(自定义唯一性标识) 查看文档示例根据主键查看文档查看所有文档 修改文档示例全局修改文档局部修改文档 删除文档示例根据文档的唯一性标识删除文档条件删除文档 本文小结…

【leetcode 447. 回旋镖的数量】审慎思考与推倒重来

447. 回旋镖的数量 题目描述 给定平面上 **n **对 互不相同 的点 points ,其中 points[i] [xi, yi] 。回旋镖 是由点 (i, j, k) 表示的元组 ,其中 i 和 j 之间的距离和 i 和 k 之间的欧式距离相等(需要考虑元组的顺序)。 返回平…

Linux引导过程和服务

一、Linux操作系统引导过程 1.引导过程 bios 加电自检——mbr——grub——加载内核——启动进程 加电后BIOS程序回自检硬件,硬件无故障后,会根据第一次启动项去找内核,一般来说第一启动项是硬盘,找到硬盘后,会根据mb…

深入了解网络流量清洗--使用免费的雷池社区版进行防护

​ 随着网络攻击日益复杂,企业面临的网络安全挑战也在不断增加。在这个背景下,网络流量清洗成为了确保企业网络安全的关键技术。本文将探讨雷池社区版如何通过网络流量清洗技术,帮助企业有效应对网络威胁。 ![] 网络流量清洗的重要性&#x…

第四站:指针的进阶-(二级指针,函数指针)

目录 二级指针 二级指针的用途 多级指针的定义和使用 指针和数组之间的关系 存储指针的数组(指针数组:保存地址值) 指向数组的指针(数组指针) 传参的形式(指针) 数组传参时会退化为指针 void类型的指针 函数指针 定义: 调用:两种方式:(*指针名)(参数地址) 或者 指针…

别闹了,真的不是你的技术菜!!!

最近经常听到有小伙伴总是在抱怨自己的技术菜,公司没有机会让自己去成长技术,于是小编就此场景来写一篇文章,希望对大家有帮助。 错误的理解CRUD工程师 CRUD工程师这个名称是很多小伙伴都听过的,并且很多工程师都把自己比作是代…

Ubuntu 18.04.5 LTS 解决安装包复杂依赖相关问题解决的主要法则和VIM的安装实录

前言:目标和环境 环境: Ubuntu 18.04.5 LTSVMware 目标: 安装vim,解决包依赖的冲突: 本文,通过一个很好的实例,诠释了,LINUX系统下,安装一个应用遇到的依赖库问题如何…

Wilcoxon秩和检验-校正P值(自备)

R语言 boxplot作图 图内展示校正后的P值(padj)_r语言 p值校正-CSDN博客 FDR错误发现率-P值校正学习_fdr和p值的关系-CSDN博客 原理介绍: Benjamini-Hochberg 方法介绍 有N次假设检验,对每一次假设检验都计算其P值,然后将计算出的P值按照…

对接讯飞聊天机器人接口--复盘

1、准备工作 1)、进入以下平台进行注册,登录后,点击红框处 2)、点击个人免费包(会弹出实名认证,先进行实名认证) 3)、认证后,会进入以下界面,先添加应用 4&am…

代码随想录刷题题Day29

刷题的第二十九天,希望自己能够不断坚持下去,迎来蜕变。😀😀😀 刷题语言:C Day29 任务 ● 01背包问题,你该了解这些! ● 01背包问题,你该了解这些! 滚动数组 …

软件测试|深入理解Python的encode()和decode()方法

简介 在Python中,字符串是不可变的序列对象,它由Unicode字符组成。当我们需要在字符串和字节之间进行转换时,Python提供了两个非常重要的方法:encode()和decode()。这两个方法允许我们在Unicode字符和字节之间进行相互转换&#…

认知能力测验,⑤破解图形推理测试题,校招社招网申在线测评必用

认知能力测试,如今是每个求职者必须要面对的,有的人可以顺顺利利通过,而有的人只能够遗憾止步。想要通过认知能力测验,并不是一件易事,而今天要说的图形推理,仅仅是其中的一个部分,抛砖引玉&…

【数据分析实战】冰雪大世界携程景区评价信息情感分析采集词云

文章目录 引言数据采集数据集展示数据预处理 数据分析评价总体情况分析本人浅薄分析 各游客人群占比分析本人浅薄分析 各评分雷达图本人浅薄分析 差评词云-可视化本人浅薄分析 好评词云-可视化本人浅薄分析 综合分析写在最后 今年冬天,哈尔滨冰雪旅游"杀疯了&q…

IP地址的网络安全防护和预防

网络安全对于保护个人和组织的信息资产至关重要,而IP地址是网络通信的基础。在这篇文章中,IP数据云将探讨IP地址的网络安全防护和预防措施,以确保网络的安全性和可靠性。 IP地址是互联网上每个设备在网络中的唯一标识符。有IPv4和IPv6两种类…

docker部署awvs

docker部署awvs cantos部署docker点这里 下载镜像 docker pull xiaomimi8/awvs14-log4j-2022 docker images 查看本地所有镜像启动镜像 docker run -it -d(后台运行) -p(端口映射) 13443(主机端口):3443&…