Python中的函数参数类型检查
Python函数参数类型检查
有一个很经典的笑话:
三个月之前,只有我和上帝知道这代码是干什么的。
现在,只有上帝知道了。
在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的一个标准库——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
上面的代码中,我们使用inspect中的signature方法获取了func的Signature对象,然后使用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:\Users\Chen\Desktop\typeassert.py", line 32, in <module>
print(add("u", 2))
File "c:\Users\Chen\Desktop\typeassert.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。
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程网。
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341