python笔记 装饰器强化下

51 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第18天,点击查看活动详情

0 环境

  • 编辑器:pycharm或者vscode
  • 系统版本:windows10
  • python版本:3.9.6

1 关键字判断

之前自写的检查函数,虽然实现了可变参数的校验,但是有时候会传入关键字,这时候怎么办呢,需要对关键字进行处理是吧,如下代码:

都知道了这里的params变量是个字典,我们在越过位置参数的判断代码,直达关键字检查这个位置,先是一个for循环,kwargs.items(),为什么可以这么用,因为是kwargs --> 字典,可以用items获取它的key, value,就是我们传入count(y=4, x=2)里的参数嘛,下面的value和该值的键下的类型注解对比,不一致,抛出异常和具体的错误信息。再次补充说明,@functools.wraps,一般都要加上,为了避免文档和函数名出现异常。inspect.signature(fn).parameters目的是要读取到被装饰器函数的所有参数(目的是类型注解),它是一个对象(返回的是整体)。不管是位置参数还是关键字,目的还是一致的,就是它的具体值和对应的函数参数的注解类型是否一致。还有一种情况就是该值对应的键没有注解类型,params[key].annotation != inspect._empty就是帮我们判断每个参数是否存在注解类型。

import functools
import typing
import inspect

def typed(fn):
    @functools.wraps(fn)
    def wrap(*args, **kwargs):
        # 检查
        params = inspect.signature(fn).parameters
        # 位置参数检查
        for index, arg in enumerate(args):
            print(index, arg)
            print(params)
            print(type(params.values()), params.values())
            param = list(params.values())[index]
            if not isinstance(arg, param.annotation):
                raise TypeError(f"parameter {param.name} required {param.annotation}, but {type(arg)}")

        # 关键字检查
        for key, value in kwargs.items():
            # kwargs里面的value是否等于params[key]里的注解
            if params[key].annotation != inspect._empty and not isinstance(value, params[key].annotation):
                raise TypeError(f"paramter {key} require {params[key].annotation}, but {type(key)}")

        return fn(*args, **kwargs)
    return wrap

@typed
def count(x: int, y: int) -> int:
    return x + y

if __name__ == '__main__':
    # count(1,2)
    count(y=4, x=2)
    # count(y=4, x="1")

2 总结

inspect库是不是很强大,很方便我们的开发,比如一下权限校验等方面。