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]范围内
相关推荐
南宫理的日知录11 分钟前
99、Python并发编程:多线程的问题、临界资源以及同步机制
开发语言·python·学习·编程学习
coberup20 分钟前
django Forbidden (403)错误解决方法
python·django·403错误
龙哥说跨境1 小时前
如何利用指纹浏览器爬虫绕过Cloudflare的防护?
服务器·网络·python·网络爬虫
小白学大数据1 小时前
正则表达式在Kotlin中的应用:提取图片链接
开发语言·python·selenium·正则表达式·kotlin
flashman9111 小时前
python在word中插入图片
python·microsoft·自动化·word
菜鸟的人工智能之路1 小时前
桑基图在医学数据分析中的更复杂应用示例
python·数据分析·健康医疗
懒大王爱吃狼2 小时前
Python教程:python枚举类定义和使用
开发语言·前端·javascript·python·python基础·python编程·python书籍
秃头佛爷3 小时前
Python学习大纲总结及注意事项
开发语言·python·学习
深度学习lover4 小时前
<项目代码>YOLOv8 苹果腐烂识别<目标检测>
人工智能·python·yolo·目标检测·计算机视觉·苹果腐烂识别
API快乐传递者5 小时前
淘宝反爬虫机制的主要手段有哪些?
爬虫·python