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]范围内
相关推荐
用户27784491049933 小时前
借助DeepSeek智能生成测试用例:从提示词到Excel表格的全流程实践
人工智能·python
JavaEdge在掘金5 小时前
ssl.SSLCertVerificationError报错解决方案
python
我不会编程5556 小时前
Python Cookbook-5.1 对字典排序
开发语言·数据结构·python
老歌老听老掉牙6 小时前
平面旋转与交线投影夹角计算
python·线性代数·平面·sympy
满怀10156 小时前
Python入门(7):模块
python
无名之逆6 小时前
Rust 开发提效神器:lombok-macros 宏库
服务器·开发语言·前端·数据库·后端·python·rust
你觉得2056 小时前
哈尔滨工业大学DeepSeek公开课:探索大模型原理、技术与应用从GPT到DeepSeek|附视频与讲义下载方法
大数据·人工智能·python·gpt·学习·机器学习·aigc
啊喜拔牙6 小时前
1. hadoop 集群的常用命令
java·大数据·开发语言·python·scala
__lost8 小时前
Pysides6 Python3.10 Qt 画一个时钟
python·qt