Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/290.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python类型化:文本类型化参数的验证修饰符_Python_Python Decorators_Python Typing_Code Inspection - Fatal编程技术网

Python类型化:文本类型化参数的验证修饰符

Python类型化:文本类型化参数的验证修饰符,python,python-decorators,python-typing,code-inspection,Python,Python Decorators,Python Typing,Code Inspection,我经常遇到函数只接受有限的值集的情况。我知道如何在类型注释中反映这种行为,使用typing.Literal如下: 导入键入 def func(a:typing.Literal['foo','bar']): 通过 我希望有一个decorator@validate\u literals,用于验证的参数是否与其类型一致: @validate\u文本 def picky_类型_函数( 二进制:正在键入.Literal[0,1], char:typing.Literal['a','b'] )->无: 通

我经常遇到函数只接受有限的值集的情况。我知道如何在类型注释中反映这种行为,使用
typing.Literal
如下:

导入键入
def func(a:typing.Literal['foo','bar']):
通过
我希望有一个decorator
@validate\u literals
,用于验证的参数是否与其类型一致:

@validate\u文本
def picky_类型_函数(
二进制:正在键入.Literal[0,1],
char:typing.Literal['a','b']
)->无:
通过
这样,输入将根据参数类型定义的限制进行验证,并且在发生冲突时会引发
ValueError

picky_-typed_函数(0,'a')#应该通过
挑剔的_类型_函数(2,'a')#应引发“ValueError:二进制必须是(0,1)'中的一个”
挑剔的_类型_函数(0,'c')#应该引发“ValueError:char必须是('a','b')中的一个”
挑剔的类型函数(0,char='c')#应该引发“ValueError:char必须是('a','b')中的一个”
挑剔的类型函数(binary=2,char='c')#应该引发“ValueError:binary必须是(0,1)中的一个”

键入
类型检查设计为静态的,不会在运行时发生。如何利用类型定义进行运行时验证?

我们可以使用检查修饰(已验证)函数的签名,通过获取参数注释的“来源”(或者,对于python版本<3.8,使用)检查函数的哪些参数被类型化为文字别名并通过使用[
键入.get_args()
])(并在嵌套的文字定义上递归迭代)从文字别名检索有效值

为了做到这一点,剩下要做的就是找出哪些参数已作为位置参数传递,并将相应的值映射到参数的名称,以便可以将该值与参数的有效值进行比较

最后,我们使用标准配方构建装饰器。最后,代码如下:

导入检查
导入键入
导入功能工具
def args_to_kwargs(func:typing.Callable,*args:list,**kwargs:dict)->dict:
args_dict={
列表(inspect.signature(func.parameters.keys())[i]:arg
对于i,枚举中的arg(args)
}
返回{**args_dict,**kwargs}
def valid_args_from_literal(注释:_GenericAlias)->Set[Any]:
args=get_args(注释)
有效的_值=[]
对于args中的arg:
如果键入.get_origin(parameter.annotation)是文字:
valid_values+=有效_args_from_literal(arg)
其他:
有效_值+=[arg]
返回集(有效的_值)
def validate_文字(func:typing.Callable)->typing.Callable:
@functools.wrapps(func)
def已验证(*args,**kwargs):
kwargs=args_至_-kwargs(func,*args,**kwargs)
inspect.signature(func.parameters.items()中的参数作为名称:
#对于<3.8的Python版本,请使用parameter.annotation.\uuuuuu origin\uuuuuu
如果键入.get_origin(parameter.annotation)正在键入.Literal:
valid_values=来自_literal的有效_参数(parameter.annotation)
如果kwargs[name]不在有效的_值中:
升值误差(
f“参数{name}必须是{valid_values}之一”
)
返回函数(**kwargs)
已验证的返回
这给出了问题中指定的结果

我还发布了python包
运行时键入
的alpha版本,以执行运行时类型检查:(文档:),它处理的情况不仅仅是
键入.Literal
,例如
键入.TypeVar
键入.Union


从valdec.dec导入验证
@证实
def func(a:Literal[“foo”,“bar”])->str:
归还
断言函数(“bar”)=“bar”
@验证(“返回”,排除=真)
def func(二进制:文本[0,1],字符:文本[“a”,“b”]):
返回二进制字符
断言函数(0,“a”)==(0,“a”)
func(2,“x”)
#valdec.utils.ValidationArgumentsError:验证错误:参数有2个验证错误
#姓名:
#二进制的
#意外值;允许:0,1(类型=值\u error.const;给定=2;
#允许=(0,1))
#煤焦
#意外值;允许:“a”、“b”(类型=值\u error.const;给定=x;
#允许=('a','b'))。
瓦尔德克: