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

这篇具有很好参考价值的文章主要介绍了优化 ParamValidator,让编辑器Pycharm智能提示校验方法。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、前置说明

1、本节目标

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

2、相关回顾

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

二、操作步骤

1、项目目录

优化 ParamValidator,让编辑器Pycharm智能提示校验方法,Python 装饰器从入门到进阶,python

  • 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, Callable

from atme.demo_validator.validator_v6.validator import Validator

Self = 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_name
        self.param_rule_des = param_rule_des

        self._validators = []

        def __getattribute__(self, name: str):
            """
            __getattribute__ 在每次访问对象的属性时都会触发,不管属性是否存在。

            以用户使用 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 相同。
            """

            # 如果获取到已存在的属性, 则使用 object.__getattribute__(self, name) 直接获取对象的属性值
            if name in ['param_name', 'param_rule_des', '_validators']:
                return object.__getattribute__(self, name)

            # 如果获取到不存在的属性,则创建了函数 validator_method
            def validator_method(*args, **kwargs):
                self._validators.append((name, args, kwargs))
                return self

            return validator_method

    def __call__(self, func: Callable) -> Callable:
        @wraps(func)
        def wrapper(*args, **kwargs):
            # 获取函数的参数和参数值
            bound_args = inspect.signature(func).bind(*args, **kwargs).arguments

            if 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 pytest

from atme.demo.validator_v6.param_validator import ParameterValidator


def test_is_string_validator_passing_01():
    """
    校验一个参数
    """

    @ParameterValidator("param").is_string(exception_msg='param must be string')
    def example_function(param):
        print(param)
        return param

    assert 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, param2

    assert 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 items

test_param_validator.py::test_is_string_validator_passing_01 PASSED      [ 50%]test
param error: "123" is invalid. due to: param must be string

test_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 可以正常智能提示可调用的校验方法:
    优化 ParamValidator,让编辑器Pycharm智能提示校验方法,Python 装饰器从入门到进阶,python

2、下节准备

  • validator 常用校验器的实现

点击进入《Python装饰器从入门到进阶》总目录文章来源地址https://www.toymoban.com/news/detail-809136.html

到了这里,关于优化 ParamValidator,让编辑器Pycharm智能提示校验方法的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 纯净Python环境的安装以及配置PyCharm编辑器

    优质的教程可以让我们少走很多弯路,这一点毋庸置疑。去年二月我接触了Python,并找到了一份优质的配置教程,让我能够快速上手Python的学习。现在,一年多过去了,我已经有了很大的进步和变化,这也让我更加想要把我的学习经验和知识分享给更多的人。正是因为有了这

    2024年02月16日
    浏览(27)
  • windows11下pycharm怎么完全卸载?完整卸载pycharm编辑器的教程

    在卸载pycharm时都有遇到卸载不干净不完全的问题,那么具体怎样做才能完全卸载pycharm呢? 一、卸载pycharm 步骤1:卸载软件并删除安装目录 我们先进入到安装的目录中,找到bin目录,点进去之后找到Uninstall.exe,执行它进行卸载,如图所示:     步骤2:删除相关的注册表 要

    2024年02月07日
    浏览(20)
  • Pycharm 配置jupyter notebook 且Windos 安装vim编辑器

    请记住要想让你的python成功安装jupyter notebook ,你的python最好使用p大于等于python3.7 最好不要在python2大版本中安装jupyternotebook 这个会报错,需要你改一些配置文件,除非你想挑战一下自己,不过后面我会尝试在python2大版本中安装,报错的原因是有的库依赖的python版本比较高,

    2024年02月06日
    浏览(31)
  • 【一个好用的智能编辑器】用于写代码很智能。Cursor代码编辑器。Cursor官网地址。

    这个编辑器发展非常快,只可惜你必须懂英文,当然,你使用少量翻译软件也可以不用懂英文的情况下仍然可以快乐的使用它。 今天在另一台机器想下载Cursor编辑器,在度娘那里竟然找不到它的地址。其中有一个微博说有分享地址,结果原来在标题~~算我眼瞎。。。。。不过

    2024年02月17日
    浏览(30)
  • web架构师编辑器内容-完成属性设置的优化

    对于业务组件来说,其属性是有很多的,如果把所有属性都平铺在页面上,就会非常长,而且想要更改其中的某些属性,可能需要向下滚动很久才能找到,对于UI的交互不是很友好,需要对属性的不同特性进行分组。 改造前: 改造后: 先来看一下通用属性: CommonComponentPro

    2024年01月22日
    浏览(20)
  • 解决ModuleNotFoundError: No module named ‘xlwt‘步骤 安装xlwt模块(编辑器:Pycharm)超详细!

    遇到如下报错:  环境中没有xlwt模块。 开始解决: ①找到安装路径: 找到解释器(Base interpreter)所在路径: (我的是)【C:Users12502AppDataLocalProgramsPythonPython36】。 打开上述路径下的【Scripts】文件,即路径:【C:Users12502AppDataLocalProgramsPythonPython36Scripts】。 复制这段

    2024年02月11日
    浏览(43)
  • Python零基础教程6——编辑器的选择(IDLE?Visual Studio Code?PyCharm?Anaconda?)

    上一节课是1-5节课复盘 大家无论之前有没有看过 都对前面的知识有了一定的了解 我在其中提到我的2023年总结 没人评论的事 没想到真有热心肠的小伙伴帮忙 再次感谢! 有评必回呀,互动起来! 这节课就是复盘之后产生的 遂 更加贴合实际! 在我们熟悉了一定的编程之后 我

    2024年01月25日
    浏览(32)
  • 【Pycharm2022.2.1】python编辑器最新版安装教程(包含2017-2022的所有版本win/mac/linux)

    前言 嗨喽~大家好呀,这里是魔王呐 ❤ ~! 永久安装 Pycharm(2017-2022的win/mac/linux所有版本)/ IntelliJ IDEA也可以, 按照本文教程所写的,具体步骤跟着下面的图文教程一步一步来就行,一分钟即可搞定,过程也非常简单。 第一步 下载pycharm安装包 官网下载链接如: 官网下载 嫌慢的

    2024年02月14日
    浏览(30)
  • 【Unity编辑器扩展】字库裁剪工具, 优化字体文件大小,批量修改文本组件字体

    原理: 1. 扫描项目中用到的字符集; 2. 把字体文件裁剪掉没用到的字符,仅保留项目中用到的字符; 3. 生成裁剪后的字体文件; 工具功能设计: 1. 支持通过拖拽字体文件或文件夹批量选择需要裁剪的字体文件。 2. 扫描工程中使用到的字符集:主要是获取prefab中Text、TextM

    2024年02月15日
    浏览(24)
  • AI文案编辑器:智能写作助手解锁你的写作灵感

    随着科技日新月异,智能AI创新应用层出不穷。值得瞩目的是,AI文案编辑器的出现,为众多用户提供了简便而强大的写作支持。该软件因其强大的功能特性以及无与伦比的便利性,得到了广泛认可及运用。接下来,我将从几个方面,阐述为何称得上AI文案编辑软件为您必备的

    2024年02月20日
    浏览(22)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包