python之装饰器强制函数上的类型检查

强颜欢笑 提交于 2019-12-05 04:27:07

问题:通过装饰器想对函数参数进行强制类型检查,并且指定所有参数类型,也可以指定部分参数类型

未装饰的函数:

def spam(x, y, z=42):
    print(x,y,z)

spam('hello',1) #hello 1 42

写装饰器前,运用到了inspect中的signature签名函数,signature()获取函数的参数签名信息

sig = signature(spam)
print(sig) #(x, y, z=42)

print(type(sig.parameters['x'].name)) #<class 'str'>
print(type(sig.parameters)) #<class 'mappingproxy'>
print(sig.parameters.items()) #odict_items([('x', <Parameter "x">), ('y', <Parameter "y">), ('z', <Parameter "z=42">)])
bind_partial() 方法来执行从指定类型到名称的部分绑定:
bound_types = sig.bind_partial(int,str,z=int) #允许忽略任何参数(int,z=int)
print(bound_types) #<BoundArguments (x=<class 'int'>, z=<class 'int'>)>
print(bound_types.arguments) #OrderedDict([('x', <class 'int'>), ('z', <class 'int'>)])
print(bound_types.arguments['x']) #<class 'int'>

bind() 跟bind_partial() 类似,但是它不允许忽略任何参数:

bound_values = sig.bind(1,2,3) #不允许忽略任何参数
print(bound_values) #<BoundArguments (x=1, y=2, z=3)>
print(bound_values.arguments) #OrderedDict([('x', 1), ('y', 2), ('z', 3)])

 

了解完这些之后,开始实现该装饰器了~

 

下面是使用装饰器技术来实现 @typeassert

from inspect import signature
from functools import wraps

def typeassert(*ty_args,**ty_kwargs):
    def decorate(func):
        if not __debug__:
            return func

        sig = signature(func)
        bound_types = sig.bind_partial(*ty_args,**ty_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(str,z=int)
def spam(x, y, z=42):
    print(x,y,z)

spam(1,'ds','www') #TypeError: Argument x must be <class 'str'>

 

 

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!