优化 ParamValidator,让编辑器Pycharm智能提示校验方法

目录

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

一、前置说明

1、总体目录

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

2、相关回顾

  • 基于 Validator 类实现 ParamValidator,用于校验函数参数

3、本节目标

  • 了解 __getattribute__ 的特性
  • 使用 __getattribute__ 结合 Validator 类中的方法,让编辑器 Pycharm 智能提示 ParamValidator 类中的方法

二、操作步骤

1、项目目录

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

2、代码实现

atme/demo/validator_v6/param_validator.py


import inspect
from functools import wraps
from typing import TypeVar, Callablefrom atme.demo.validator_v6.validator import ValidatorSelf = TypeVar('Self', bound='ParameterValidator')class ParameterValidator:def __init__(self, param_name: str, param_rule_des=None):""":param param_name: 参数名:param param_rule_des: 该参数的规则描述"""self.param_name = param_nameself.param_rule_des = param_rule_desself._validators = []def __getattribute__(self, name: str):"""__getattribute__ 在每次访问对象的属性时都会触发,不管属性是否存在。通过重写 __getattribute__,可以自定义属性的获取逻辑,实现了对特定属性的直接访问(param_name 、param_rule_des 、 _validators),而对于其他属性,则创建名为 validator_method 的函数,将其作为属性返回"""'''如果获取到的属性名为 param_name 、param_rule_des 、 _validators , 则使用 object.__getattribute__(self, name) 直接获取对象的属性值。不对 self.param_name 、 self.param_rule_des 、 self._validators 做改变'''if name in ['param_name', 'param_rule_des', '_validators']:return object.__getattribute__(self, name)'''如果属性名不在上述列表中,说明用户正在访问一个不存在的属性,这时创建了一个函数 collect_validator_method以用户使用 ParamValidator("param").is_string(exception_msg='param must be string').is_not_empty() 为例,代码执行过程如下:1. 当用户调用 ParamValidator("param").is_string(exception_msg='param must be string') 时,2. 由于 is_string 方法不存在,__getattr__ 方法被调用,返回 validator_method 函数(此时未被调用),is_string 方法实际上是 validator_method 函数的引用,3. 当执行 is_string(exception_msg='param must be string') 时,is_string 方法被调用, 使用关键字参数传递 exception_msg='param must be string',4. 实际上是执行了 validator_method(exception_msg='param must be string') , validator_method 函数完成调用后,执行函数体中的逻辑:- 向 self._validators 中添加了一个元组 ('is_string', (),  {'exception_msg': 'param  must  be  string'})- 返回 self 对象5. self 对象继续调用 is_not_empty(), 形成链式调用效果,此时的 validator_method 函数的引用就是 is_not_empty, 调用过程与 1-4 相同。'''def validator_method(*args, **kwargs):self._validators.append((name, args, kwargs))return selfreturn validator_methoddef __call__(self, func: Callable) -> Callable:@wraps(func)def wrapper(*args, **kwargs):# 获取函数的参数和参数值bound_args = inspect.signature(func).bind(*args, **kwargs).argumentsif self.param_name in kwargs:# 如果函数被装饰,且以关键字参数传值,则从 kwargs 中取参数值value = kwargs[self.param_name]else:# 如果函数被装饰,且以位置参数传值,则从 bound_args 中取参数值value = bound_args.get(self.param_name)# 实例化 Validator 对象validator = Validator(value, field=self.param_name, rule_des=self.param_rule_des)# 遍历所有校验器(注意:这里使用 vargs, vkwargs,避免覆盖原函数的 args, kwargs)for method_name, vargs, vkwargs in self._validators:# 通过 函数名 反射获取校验函数对象validate_method = getattr(validator, method_name)# 执行校验函数validate_method(*vargs, **vkwargs)# 执行原函数return func(*args, **kwargs)return wrapper'''==============================分隔符===============================以下所有方法,是从 Validator 类中复制过来,目的是:- 让编辑器如 Pycharm 智能提示 ParameterValidator 本类中可以使用的校验方法;- 这些方法仅供 Pycharm 智能提示使用,没有任何实际作用;可以是:def is_string(self, exception_msg=None) -> Self:...也可以是:def is_string(self, exception_msg=None) -> Self:return isinstance(self.value, str)            - ParameterValidator 类的实例通过 __getattribute__ 方法动态收集用户的调用方法;- 然后使用 __call__ 方法反射调用 Validator 类中的调用方法在模块中定义了: Self = TypeVar('Self', bound='ParameterValidator'),目的是:- 方便从 Validator 类中复制校验方法,粘贴之后不做任何代码层面的修改:- 方便链式调用,如: @ParameterValidator("param").is_string().is_not_empty()'''def is_string(self, exception_msg=None) -> Self:return isinstance(self.value, str)def is_not_empty(self, exception_msg=None) -> Self:return bool(self.value)

3、测试代码

atme/demo/validator_v6/test_param_validator.py


import pytestfrom atme.demo.validator_v6.param_validator import ParameterValidatordef test_is_string_validator_passing_01():"""校验一个参数"""@ParameterValidator("param").is_string(exception_msg='param must be string')def example_function(param):print(param)return paramassert example_function(param="test") == "test"with pytest.raises(ValueError) as exc_info:example_function(param=123)print(exc_info.value)assert "invalid" in str(exc_info.value)def test_is_string_validator_passing_02():"""校验多个参数"""@ParameterValidator("param2").is_string().is_not_empty()@ParameterValidator("param1").is_string().is_not_empty()def example_function(param1, param2):print(param1, param2)return param1, param2assert example_function("test1", "test2") == ("test1", "test2")with pytest.raises(ValueError) as exc_info:example_function(123, 123)print(exc_info.value)assert "invalid" in str(exc_info.value)

4、日志输出

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

============================= test session starts =============================
collecting ... collected 2 itemstest_param_validator.py::test_is_string_validator_passing_01 PASSED      [ 50%]test
param error: "123" is invalid. due to: param must be stringtest_param_validator.py::test_is_string_validator_passing_02 PASSED      [100%]test1 test2
param2 error: "123" is invalid.============================== 2 passed in 0.01s ==============================

三、后置说明

1、要点小结

  • __getattribute__ 在每次访问对象的属性时都会触发,不管属性是否存在。
  • 通过重写 __getattribute__,可以自定义属性的获取逻辑,实现了对特定属性的直接访问(param_nameparam_rule_des_validators),而对于其他属性,则创建名为 validator_method 的函数,将其作为属性返回。
  • Validator 类中复制过来的校验方法,是为了让编辑器如 Pycharm 智能提示 ParameterValidator 本类中可以使用的校验方法,没有任何实际作用。
  • 在模块中定义 Self = TypeVar('Self', bound='ParameterValidator'),方便链式调用,如 @ParameterValidator("param").is_string().is_not_empty()
  • 经过优化后,Pycharm 可以正常智能提示可调用的校验方法:

2、下节准备

  • validator 常用校验器的实现

点击返回主目录

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

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

相关文章

基于JavaWeb+BS架构+SpringBoot+Vue基于web的多媒体素材管理系统的设计和实现

基于JavaWebBS架构SpringBootVue基于web的多媒体素材管理系统的设计和实现 文末获取源码Lun文目录前言主要技术系统设计功能截图订阅经典源码专栏Java项目精品实战案例《500套》 源码获取 文末获取源码 Lun文目录 1 绪 论 1 1.1选题背景与意义 1 1.1 研究背景 1 1.2 研究意义…

网络安全工具:通过监控分析日志数据保护企业网络

由于混合工作模式的兴起以及业务运营向云环境的迁移,企业网络变得更加分散和复杂,仅安装外围安全解决方案只会创建一个基本的防御层,系统、服务器和其他网络实体会生成记录所有网络活动的日志。集中式日志管理系统可以帮助管理员自动监控网络…

手机直连卫星及NTN简介

一、手机直连卫星的发展现状 近日,华为推出了支持北斗卫星短报文的Mate 50旗舰机、P60系列,苹果也跟Globalstar(全球星)合作推出了支持卫星求救的iPhone14,最亮眼的还是华为的。这几款产品揭开了卫星通信探索消费领域…

Spring MVC 参数传递和JSON数据处理

参数传递 ModelAndView传递 编写controller Controller RequestMapping("/account") public class AccountController { ​//也可以不创建ModelAndView,直接在参数中指定RequestMapping(value "/findAccount9")public ModelAndView findAccou…

美国证券交易委员会 X 账户被黑,引发比特币市场震荡

Bleeping Computer 网站消息,威胁攻击者成功“占领”了美国证券交易委员会的 X 账户,并发布一条关于批准比特币 ETF 在证券交易所上市的虚假公告。 帖子原文:今天,美国证券交易委员会批准比特币 ETF 在注册的国家证券交易所上市&a…

MySQL:索引失效场景总结

1 执行计划查索引 通过执行计划命令可以查看查询语句使用了什么索引。 EXPLAIN SELECT * FROM ods_finebi_area WHERE areaName = 福建 执行查询计划后,key列的值就是被使用的索引的名称,若key列没有值表示查询未使用索引。 2 在什么列上创建索引 (1)列经常被用于where…

Map与JSONObject区别

相同点: 都可以存key-value;key是唯一的,如果key重复了会覆盖前面的 不同点: (1)JSONObject 不可以存空,Map可以存空。 (2)Map由jdk提供,JsonObject需要第三方jar包提供。…

XUbuntu22.04之快速复制绝对路径(二百零五)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 优质专栏:多媒…

Windows启动MongoDB服务报错(错误 1053:服务没有及时响应启动或控制请求)

问题描述:修改MongoDB服务bin目录下的mongod.cfg,然后在任务管理器找到MongoDB服务-->右键-->点击【开始】,启动失败无提示: 右键点击任务管理器的MongoDB服务-->点击【打开服务】,跳转到服务页面-->找到M…

一级倒立摆控制 - 非线性 MPC 控制及 MATLAB 实现

系列文章目录 前言 本示例使用非线性模型预测控制器对象和块实现对小车上倒立摆的摆动和平衡控制。 本示例需要 Optimization Toolbox™ 软件为非线性 MPC 提供默认的非线性编程求解器,以计算每个控制间隔的最优控制动作。 一、摆锤/小车装配 本例中的被控对象是…

ChatGPT本地部署,学习记录

一、GPT4ALL模型 官网地址: Github:https://github.com/nomic-ai/gpt4all GPT4ALL项目部署简易,但是在运行体验上一般,并且是只调用CPU来进行运算。 看官方文档介绍在嵌入式上有比较大的优势,但是目前个人对嵌入式…

ffmpeg写YUV420文件碰到阶梯型横线或者条纹状画面的原因和解决办法

版权声明:本文为CSDN博主「文三~」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/asdasfdgdhh/article/details/112831581 留作备份 阶梯型横线: 条纹状画面…

CloudCompare——拟合空间球

目录 1.拟合球2.软件操作3.算法源码4.相关代码 本文由CSDN点云侠原创,CloudCompare——拟合空间球,爬虫自重。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫与GPT生成的文章。 1.拟合球 源码里用到了四点定球,…

[笔记]学习做微信小程序

学习视频:前端微信小程序开发教程 本篇文章 只对关键内容笔记,用于自用。 这里写目录标题 注册、下载、安装我的小程序ID:wxe1fbd6939d8797d8我的小游戏ID:wx8b2c3e47ac9127b7开发者工具外观代理设置 创建第一个小程序主界面5个组…

QT开发 2024最新版本优雅的使用vscode开发QT

▬▬▬▬▬▶VS开发QT◀▬▬▬▬▬ 🎄先看效果 🎄编辑环境变量 如图添加环境变量!!! 东西全在QT的安装目录!!! 找到的按照我的教程再装一次!!! 点…

postman 之 接口请求

一、前言 1. 安装 2. 主界面 3. 请求区域 Body下主要包含以下4中格式 form-data:混合表单,支持上传文件x-www-form-urlencoded:文本表单raw:原始格式,支持JSON/XML格式(后面可选择)binary&am…

Camunda Event Based Gateway

一:bpmn 二:java 如果没有收到信号,超过等待时间,流程进入总经理审批,如果在等待时间内收到信号,流程进入副总经理审批。 示例1:发送信号事件,流程进入副总经理审批。 repository…

yolo 分割label格式标注信息图片显示可视化查看

参考: https://github.com/ultralytics/ultralytics/issues/3137 https://blog.csdn.net/weixin_42357472/article/details/135218349?spm=1001.2014.3001.5501 需要把坐标信息在图片上显示 代码 1)只画出了坐标边缘 import cv2 import numpy as np from random impor…

AlexNet论文精读

1:该论文解决了什么问题? 图像分类问题 2:该论文的创新点? 使用了大的深的卷积神经网络进行图像分类;采用了两块GPU进行分布式训练;采用了Relu进行训练加速;采用局部归一化提高模型泛化能力;…

通过反射修改MultipartFile类文件名

1、背景 项目上有这样一个需求&#xff0c;前端传文件过来&#xff0c;后端接收后按照特定格式对文件进行重命名。(修改文件名需求其实也可以在前端处理的) //接口类似于下面这个样子 PosMapping("/uploadFile") public R uploadFile(List<MultipartFile> fil…