编写装饰器并保存函数的元数据,代码简洁之道
2018-09-16 17:40
851 查看
软件开发中的重要一条真理就是“不要重复自己的工作”。通常当我们需要创建高度重复的代码时,都可以寻找到一个更加优雅的解决方案。1 给函数添加一个包装,让它做一点额外的工作 当我们需要让一个函数拥有计时统计、打印日志的功能时,往往选择的方案就是直接在函数体中增加需要的代码。这在只有一两个函数的时候还可以接受,但是如果需要让一个项目中的所有函数都具有这样的功能时,就会变得十分繁琐。 这时候,就需要我们使用“装饰器”了。示例如下:
from functools import wraps import time def logit(func): ''' 使用装饰器来打印函数调用信息 ''' @wraps(func) def wrapper(*args, **kwargs): print('start func {}'.format(func.__name__), time.strftime('at %Y %m %d %H:%M:%S', time.localtime())) result = func(*args, **kwargs) print('finish func {}'.format(func.__name__), time.strftime('at %Y %m %d %H:%M:%S', time.localtime())) return result return wrapper下面是使用演示:
>>> @logit def countdown(n): while(n > 0): n -= 1 >>> countdown(10000000) start func countdown at 2018 09 16 16:45:23 finish func countdown at 2018 09 16 16:45:24只需要在函数定义时为它增加一个装饰器(@logit),这个函数就能告诉我们它开始运行的时间以及结束运行的时间! 装饰器其实就是一个函数,它可以接受一个函数作为输入并返回一个新的函数作为输出。 装饰器内部的代码一般会涉及创建一个新的函数,利用*args和**kwargs可以接收任意的参数。在这个函数内部,我们调用原来的输入函数(即被包装的那个函数,它是装饰器的输入参数)并返回它的结果。此时,这个新创建的wrapper函数就会作为装饰器的结果返回,取代了原本的函数。 需要强调的一点是,装饰器一般来说不会修改调用的签名,也不会修改被包装函数返回的结果。这里使用了*args和**kwargs来确保可以接受任何形式的输入参数。装饰器的返回值几乎总是同调用func(*args,**kwargs)的结果一致,这里的func就是那个未被包装过的原始函数。2 那装饰器函数中的装饰器@wraps有什么作用 装饰器@wraps可以用来保存底层的元数据,比如函数名、文档字符串、函数注解以及调用签名。 如果没有使用该装饰器,获取上一个例子中countdown函数的元数据就会看起来像这样:
>>> countdown.__name__ 'wrapper' >>> countdown.__doc__ >>> countdown.__annotations__@wraps的另一个重要特性就是可以通过__wrapped__属性来访问那个被包装的函数,而该属性同时也可以使得装饰器函数可以合适的将底层被包装的函数的签名暴露出来:
>>> from inspect import signature >>> print(signature(countdown)) (n:int)
相关文章推荐
- 9-2为被装饰的函数保存元数据
- 【笔记】如何为被装饰的函数保存元数据
- python 9-2 如何为被装饰的函数保存元数据,使用标准库functools中的装饰器wraps 装饰内部包裹函数
- python-为被装饰的函数保存元数据-26
- php中将数组转成字符串并保存到数据库中的函数代码
- 计算机笔试题:写一个函数,检查字符是否是整数,如果是,返回其整数值。(或者:怎样只用4行代码编写出一个从字符串到长整型的函数)
- 编写更加简洁的JS代码
- Java下的Framework编写(反射,泛型,元数据,CGLib,代码动态生成,AOP,动态语言嵌入)(1)--序
- 第四章 代码重用与函数编写
- 分享10个帮助你编写更加简洁javascript代码的小技巧
- 编写一个函数itob(int num,char s[], int n),将整数num转换为以n进制的数。保存到s中。
- 提高代码质量:如何编写函数
- 提高代码质量:如何编写函数
- 如何编写函数才能提高代码质量
- 编写函数int stat(int a[],int n,int c[][2])。a指向的数组中保存了由n个1位整数组成的数列(n为偶数)。函数从前至后依次将a数组中每两个相邻元素拼成一个不超过2位的
- 编写函数int stat(int a[],int n,int c[][2])。a指向的数组中保存了由n个1位整数组成的数列(n为偶数)。函数从前至后依次将a数组中每两个相邻元素拼成一个不超过2位
- PHP代码重用与函数编写
- 编写高质量代码——运算符重载,是成员函数还是友元函数
- Java下的Framework编写(反射,泛型,元数据,CGLib,代码动态生成,AOP,动态语言嵌入)(1)--序
- 浅析Python编写函数装饰器