ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

使用装饰器完成python运行时类型检查

2021-05-15 15:32:45  阅读:148  来源: 互联网

标签:检查 python bound int sig 参数 type 装饰


python运行时类型检查

  1. 参数类型检查装饰器设计
    请紧跟我的思路来设计这个可以检查函数参数类型的装饰器

1.1 装饰器带参数
首先,这个装饰器必须允许传入参数,这样,我们才能在使用装饰器修饰函数的时候指定参数的类型

@typecheck(int, int)
def add(x, y):
    return x + y

1.2 获得被装饰的函数的形参列表
其次,必须在函数参数和我们所规定的参数之间建立起一个映射关系,指明参数x的类型是int, 参数y的类型是int, 在装饰器里,我们必须能够拿到被装饰函数的参数,这个倒是不难,使用inspect模块的signature方法就可以

from inspect import signature

def add(x, y):
    return x + y

sig = signature(add)
print(sig, type(sig))

程序输出结果

(x, y) <class 'inspect.Signature'>

1.3 建立映射关系
接下来,要在函数参数列表和我们装饰器里传入的参数之间建立映射关系, 这个可以使用bind_partial方法

sig = signature(add)
print(sig, type(sig))

bound_types = sig.bind_partial(int, int).arguments
print(bound_types)

程序输出结果

OrderedDict([('x', <class 'int'>), ('y', <class 'int'>)])

1.4 获取函数的实参列表
已经知道了函数的参数的约定类型,在实际执行代码时,还有能够获得函数实际传入的参数数值,也就是实参列表,这个可以通过bind方法来获得

from inspect import signature

def add(x, y):
    sig = signature(add)
    bound_values = sig.bind(x, y)
    print(bound_values)


add(1, 4)

程序输出结果

<BoundArguments (x=1, y=4)>

1.5 检查参数类型
1.3 获取到参数的约定类型,1.4获取函数执行时实际传入的实参,那么就可以进行类型检查了,当实际传入参数类型与约定不符时则抛出异常

  1. 装饰器实现与使用
    前面的设计,每一步都只解决一个小问题,现在,综合所有已经探索的技术来完成这个装饰器
from inspect import signature
from functools import wraps


def typecheck(*type_args, **type_kwargs):
    '''
    类型检查装饰器, type_args和type_kwargs都是装饰器的参数
    :param type_args:
    :param type_kwargs:
    :return:
    '''
    def decorator(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 decorator

@typecheck(int, int)
def add(x, y):
    return x + y

add(3, 4.5)

使用该装饰器指定参数类型非常灵活,可以使用关键字参数

@typecheck(int, z=float)
def test(x, y, z):
    print(x, y, z)

test(1, '2', 5.4)
test(1, 2, 5.4)

只用位置参数约定了函数的第一个参数类型必须是int,使用关键字参数z=float约定了参数z的类型必须是float,对于参数y没有任何要求,那么参数传入任何类型的数据都可以,装饰器不会进行检查

标签:检查,python,bound,int,sig,参数,type,装饰
来源: https://www.cnblogs.com/fly-book/p/14771671.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有