在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:\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

Python 带参数的装饰器 [2] 函数参数类型检查的更多相关文章

  1. python:带参数的装饰器,函数的有用信息

    一.带参数的装饰器,函数的有用信息 def func1(): '''此函数的功能是完成的登陆的功能 return: 返回值是登陆成功与否(true,false) ''' print(333) func ...

  2. 【python 】装饰器 (多个参数的函数,带参数的装饰器)【转】

    最简单的模板是这样的 #-*-coding:utf-8-*- def outer(func): def inner(): print 'before' func() print 'after' # r ...

  3. python 装饰器 (多个参数的函数,带参数的装饰器)

    最简单的模板是这样的 #-*-coding:utf-8-*- def outer(func): def inner(): print 'before' func() print 'after' # r ...

  4. guxh的python笔记三:装饰器

    1,函数作用域 这种情况可以顺利执行: total = 0 def run(): print(total) 这种情况会报错: total = 0 def run(): print(total) tot ...

  5. Python进阶(七)----带参数的装饰器,多个装饰器修饰同一个函数和递归简单案例(斐波那契数列)

    Python进阶(七)----带参数的装饰器,多个装饰器修饰同一个函数和递归简单案例(斐波那契数列) 一丶带参数的装饰器 def wrapper_out(pt): def wrapper(func): ...

  6. Python之函数的进阶(带参数的装饰器)

    函数篇--装饰器二 带参数的装饰器 def outer(flag): def timer(func): def inner(*args,**kwargs): if flag: print('''执行函 ...

  7. python 全栈开发,Day12(函数的有用信息,带参数的装饰器,多个装饰器装饰一个函数)

    函数的执行时,*打散.函数的定义时,*聚合. from functools import wraps def wrapper(f): # f = func1 @wraps(f) def inner(* ...

  8. python全栈开发day12-函数的有用信息、带参数的装饰器、多个装饰器装饰一个函数、global和nonlocal的进一步解析和总结

    1.上周回顾 1).函数名的应用 直接打印函数名,是函数的地址 变量 函数的参数 函数的返回值 可以当容器类数据类型的元素 2).闭包 内层函数对外层函数的非全局变量的引用,就是闭包. 并返回内部函数 ...

  9. Python带参数的装饰器

    在装饰器函数里传入参数 # -*- coding: utf-8 -*- # 2017/12/2 21:38 # 这不是什么黑魔法,你只需要让包装器传递参数: def a_decorator_passi ...

随机推荐

  1. 【转】hibernate 延迟加载

    Hibernae 的延迟加载是一个非常常用的技术,实体的集合属性默认会被延迟加载,实体所关联的实体默认也会被延迟加载.hibernate 通过这种延迟加载来降低系统的内存开销,从而保证 Hiberna ...

  2. EF实现增删改查

    从来没想到过能在这个上面翻车,感慨自学没有培训来得系统啊,废话不多说 ORM:对象关系映射(Object Relational Mapping,简称ORM,或O/RM,或O/R mapping),是一 ...

  3. C# SqlBulkCopy类批量导入 测试

    一.功能说明 1.可以选择,只导入部分列,或者导入全部列. 2.导入速度的确比一般sql要快. 3.不用写sql语句 ----------------------------------------- ...

  4. K8S 部署 ingress-nginx (二) 部署后端为 tomcat

    在上面已经部署了 ingress-nginx, https://www.cnblogs.com/klvchen/p/9903480.html 创建 service 和 pods cd vi tomca ...

  5. Android的ToolBar

    ToolBar比ActionBar更加可控,自由.因此,Google 逐渐使用ToolBar来代替ActionBar. 使用ToolBar 1.要引入appCompat_v7支持 2.主题设置为NoA ...

  6. 常用的JVM调优参数总结汇总【随时查阅学习】

    本文章参数根据后期用的参数会持续更新  --- (1)-Xms20M 表示设置JVM启动内存的最小值为20M,必须以M为单位 (2)-Xmx20M 表示设置JVM启动内存的最大值为20M,必须以M为单 ...

  7. 页面间固定参数,通过cookie传值

    最后在做的页面,比如用户数据(用户头像,名称,年龄)这些信息,因为大部分页面都要用,之前是通过url地址传,另一页面接收.考虑到这样做会让url过长,因此,尝试使用cookie,把固定的值保存在coo ...

  8. Team Services的打包管理

    Team Services的打包管理 概述 Package Management (打包管理)是一种扩展,可以更容易地发现.安装和发布包. 它与Team Services中心如构建功能深度集成,这样打 ...

  9. Could not update the distribution database subscription table. The subscription status could not be changed.

    在一个测试服务器删除发布(Publication)时遇到下面错误,具体如下所示 标题: Microsoft SQL Server Management Studio   --------------- ...

  10. GIT基本命令介绍

    1.git remote git remote -v| --verbose 查看仓库详细信息 git remote add <name> <url> 关联远程库.如果你本地新建 ...