• Python 带参数的装饰器 [2] 函数参数类型检查


    在Python中,不知道函数参数类型是一个很正常的事情,特别是在一个大项目里。
    我见过有些项目里,每一个函数体的前十几行都在检查参数类型,这实在是太麻烦了。而且一旦参数有改动,这部分也需要改动。
    下面我们用装饰器来实现,函数参数的强制类型检查。

     

    首先,这个装饰器,要接受类型参数,和指定函数参数的类型参数。也就是一个list和一个dict

    from functools import wraps
    
    def typeassert(*type_args, **type_kwargs):
        def decorate(func):
            @wraps(func)
            def wrapper(*args, **kwargs):
                return func(*args, **kwargs)
            return wrapper
        return decorate

    @wraps(func)的作用请看前一篇Python装饰器 [1]

    那么,接下来,在装饰器中,我们需要获取函数参数列表,并且要和类型参数表映射。
    这要借助Python的一个标准库——inspect 这个库一般用于Python代码调试

    from inspect import signature
    from functools import wraps
    
    def typeassert(*type_args, **type_kwargs):
        def decorate(func):
            sig = signature(func)
            bound_types = sig.bind_partial(*type_args, **type_kwargs).arguments
    
            @wraps(func)
            def wrapper(*args, **kwargs):
                return func(*args, **kwargs)
            return wrapper
        return decorate

    两层闭包三个def函数 = 带参数的装饰器 

    上面的代码中,我们使用inspect中的signature方法获取了funcSignature对象,然后使用bind_partial方法创建了(*type_args, **type_kwargs)func参数的映射(也就是一个字典)。

     

    接下来就简单了,我们只需要再获取(*args, **kwargs)的类型,使用isintance函数进行比较就好。

    from inspect import signature
    from functools import wraps
    
    def typeassert(*type_args, **type_kwargs):
        def decorate(func):
            sig = signature(func)
            bound_types = sig.bind_partial(*type_args, **type_kwargs).arguments
    
            @wraps(func)
            def wrapper(*args, **kwargs):
                bound_values = sig.bind(*args, **kwargs)
                for name, value in bound_values.arguments.items():
                    if name in bound_types:
                        if not isinstance(value, bound_types[name]):
                            raise TypeError('Argument {} must be {}'.format(name, bound_types[name]))
                return func(*args, **kwargs)
            return wrapper
        return decorate

    运行如下代码

    @typeassert(int, int)
    def add(x, y):
        return x+y
    
    print(add("u", 2))

    能看到报错如下

    Traceback (most recent call last):
      File "c:UsersChenDesktop	ypeassert.py", line 32, in <module>
        print(add("u", 2))
      File "c:UsersChenDesktop	ypeassert.py", line 22, in wrapper
        'Argument {} must be {}'.format(name, bound_types[name])
    TypeError: Argument x must be <class 'int'>

    很贴心的提醒了我们哪一个参数应该是什么类型。你甚至可以自己改动这个装饰器,让它还能告诉你传进去了什么错误参数(特别是写爬虫的时候,参数很难掌握,一旦报错,还得重跑一遍才知道为什么。)

     

    你也可以指定某一个参数的类型,譬如

    @typeassert(int, z=str)
    def display(x, y, z):
        print(x, y, z)

    这时你会发现,y的类型就像原生的Python函数一样,什么都行。而x必须是int,z必须是str

     

  • 相关阅读:
    h.264宏块与子宏块类型
    h.264语法结构分析
    [傅里叶变换及其应用学习笔记] 关于任何信号都能表现成傅里叶级数形式的推导
    [傅里叶变换及其应用学习笔记] 课程概览
    [傅里叶变换及其应用学习笔记] 三十. 拉东变换
    [傅里叶变换及其应用学习笔记] 二十九. 高维Ш函数修改版
    后端解决 微信H5支付 商户参数格式错误 方法
    PhpStorm一次性折叠所有函数或者方法
    js生成的cookie在yii2中获取不到的解决办法
    Android webview 调起H5微信支付
  • 原文地址:https://www.cnblogs.com/clemente/p/10233467.html
Copyright © 2020-2023  润新知