python装饰器验证位置.关键字.默认参数的有效范围

1 python装饰器验证位置.关键字.默认参数的有效范围

python验证位置参数、关键字参数、默认参数的有效范围。

1.1 func.code

python可以查看函数的名称、函数变量、入参个数等属性。参考《python函数属性和注解

NO 属性 描述
1 func.name 函数名
2 func.code 函数代码对象
3 func.code.co_varnames 函数全部变量
4 func.code.co_argcount 函数入参个数

1.2 装饰器验证位置、关键字传参的有效范围

描述

将入参及有效范围保存在字典,对实际接收到的入参值进行有效范围验证。

(1) 最外层定义rangetest,入参argchecks将装饰函数或方法的入参和有效范围保存为字典,即保存需验证的入参有效范围;

(2) 次外层定义onDecorator,入参func保存装饰函数或方法;

(3) 最里层定义onCall,入参接收装饰函数或方法的位置和关键字入参;

(4) co_varnames:code.co_argcount获取装饰函数或方法定义的全部入参;

(5) pargs保存装饰函数或方法的实际位置入参值;

(6) kargs保存装饰函数或方法的实际关键字入参名和值;

(7) 需验证有效范围的入参名在实际关键字入参内,则进行校验;

(8) 需要在有效范围的入参名在实际位置入参内,则进行校验;

(9) 剩下的为默认入参,不校验;

示例

python 复制代码
>>> import inspect
>>> def get_default_args(func):
    #获取入参默认值
    signature = inspect.signature(func)
    return {
        k: v.default
        for k, v in signature.parameters.items()
        if v.default is not inspect.Parameter.empty
    }
>>> def rangetest(**argchecks):
    #argchecks 参数字段,入参名为键,有效范围为值,传入需要验证的参数和范围
    def onDecorator(func):#接收函数或方法
        if not __debug__:#内置变量,默认True
            return func
        else:
            defaultargs=get_default_args(func)
            code=func.__code__
            allargs=code.co_varnames[:code.co_argcount]
            funcname=func.__name__
            def onCall(*pargs,**kargs):#函数或方法入参,支持位置和关键字传参
                positionals=list(allargs)
                positionals=positionals[:len(pargs)]
                
                for (argname,(low,high)) in argchecks.items():
                    # 遍历argchecks验证入参有效范围
                    if argname in kargs:#关键字传参验证
                        if kargs[argname]<low or kargs[argname]>high:
                            errmsg='{}入参"{}"的值 {} 不在[{},{}]范围内'
                            errmsg=errmsg.format(funcname,argname,kargs[argname],low,high)
                            raise ValueError(errmsg)
                    elif argname in positionals:#位置传参验证
                        position=positionals.index(argname)
                        if pargs[position]<low or pargs[position]>high:
                            errmsg='{}入参"{}"的值 {} 不在[{},{}]范围内'
                            errmsg=errmsg.format(funcname,argname,pargs[position],low,high)
                            raise ValueError(errmsg)
                    else:#参数默认值不验证
                        msg='{}入参 "{}"取默认值 {}'
                        print(msg.format(funcname,argname,defaultargs[argname]))
                return func(*pargs,**kargs)
            return onCall
    return onDecorator

>>> def exDecorator(func):
    def onCall(*args,**kargs):
        try:
            return func(*args,**kargs)
        except ValueError as ve:
            print(ve)
    return onCall

1.3 验证函数入参有效范围

描述

通过装饰器入参的k指定验证入参的名字,v指定验证入参的有效范围。

@rangetest(age=(0,120))的age表示persinfo(name,age)函数要验证的入参为age入参,0,120表示,age的有效范围为0,120

示例

python 复制代码
>>> @exDecorator
@rangetest(age=(0,120))#1 表示验证persinfo索引为1的入参age的范围
def persinfo(name,age):
    print('%s 今年 %s 岁' %(name,age))

    
>>> @exDecorator
@rangetest(Y=(0,2999),M=(1,12),D=(1,31))#对Y,M,D都验证
def birthday(Y,M,D):
    print('生日={0}年{1}月{2}日'.format(Y,M,D))

>>> persinfo('梯阅线条',36)
梯阅线条 今年 36 岁
>>> persinfo('梯阅线条',121)
persinfo入参"age"的值 121 不在[0,120]范围内
>>> birthday(2023,10,21)
生日=2023年10月21日
>>> birthday(3023,10,21)
birthday入参"Y"的值 3023 不在[0,2999]范围内
>>> birthday(2023,13,21)
birthday入参"M"的值 13 不在[1,12]范围内
>>> birthday(2023,12,51)
birthday入参"D"的值 51 不在[1,31]范围内

1.4 验证方法入参有效范围

描述

通过装饰器入参的k指定验证入参的名字,v指定验证入参的有效范围。

@rangetest(percent=(0.0,1.0))的percent表示giveRaise(self,percent)方法要验证的入参为percent入参,0.0,1.0表示,percent的有效范围为0.0,1.0

示例

python 复制代码
>>> class Person:
    def __init__(self,name,job,pay):
        self.job=job
        self.pay=pay
    @exDecorator
    @rangetest(percent=(0.0,1.0))
    def giveRaise(self,percent):
        self.pay=int(self.pay*(1+percent))

        
>>> p1=Person('梯阅线条','自由职业',500000)
>>> p1.giveRaise(0.2)
>>> p1.pay
600000
>>> p1.giveRaise(1.2)
giveRaise入参"percent"的值 1.2 不在[0.0,1.0]范围内

1.5 验证位置、关键字传参范围

描述

@rangetest*(a=(1,10),b=(2,20),c=(3,30),d=(5,50))的a,b,c,d表示要验证的入参和对应的有效范围。支持位置传参、关键字传参及默认传参的有效范围校验。

示例

python 复制代码
>>> @exDecorator
@rangetest(a=(1,10),b=(2,20),c=(3,30),d=(5,50))
def mixargs(a,b=7,c=8,d=9):
    print(a,b,c,d)

    
>>> mixargs(1,2,3,5)
1 2 3 5
>>> mixargs(1)
mixargs入参 "b"取默认值 7
mixargs入参 "c"取默认值 8
mixargs入参 "d"取默认值 9
1 7 8 9
>>> mixargs(d=9,c=8,a=2)
mixargs入参 "b"取默认值 7
2 7 8 9
>>> mixargs(5,d=9,c=8)
mixargs入参 "b"取默认值 7
5 7 8 9
>>> mixargs(11,d=9,c=8)
mixargs入参"a"的值 11 不在[1,10]范围内
>>> mixargs(2,d=91,c=8)
mixargs入参 "b"取默认值 7
mixargs入参"d"的值 91 不在[5,50]范围内
相关推荐
笨鸟先飞,勤能补拙4 小时前
AI 赋能网络安全:技术全景、成熟度评估与实战案例
人工智能·python·安全·web安全·网络安全·sqlite·github
长和信泰光伏储能5 小时前
京津冀光伏发电:绿色能源的未来之路
python·能源
浦信仿真大讲堂5 小时前
从重复操作到自动化闭环:如何让 CST 与 Python 真正协同起来
python·自动化·cst·仿真软件·达索软件
Gu Gu Study6 小时前
ScoutLoop开放域深度研究引擎(agent的初步设计想法)
人工智能·python
卷无止境6 小时前
写代码这件事,到底该讲究点什么?
后端·python
卷无止境6 小时前
循环复杂度到底在算什么,Python 代码怎么才能写得让人一看就懂
后端·python
lpfasd1236 小时前
MediaCrawler 项目深度分析
chrome·python·chrome devtools
Dxy12393102167 小时前
Python项目打包成EXE完整教程(PyInstaller实战避坑)
开发语言·python
bamb007 小时前
一个项目带你入门AI应用开发01
python
0566468 小时前
Python康复训练——常用标准库
开发语言·python·学习