Python 基础 —— 装饰器(1)
来源:互联网 发布:spc数据输出 编辑:程序博客网 时间:2024/06/06 10:44
由于函数也是一个对象,而且函数对象可以被赋值给变量,所以,通过变量也能调用该函数。
In [46]: def now(): ...: print(my_str) ...:In [47]: f=now()09:50:25
函数对象有一个__name__
属性,可以拿到函数的名字:
In [52]: f.__name__Out[52]: 'now'
现在,假设我们要增强now()函数的功能,比如,在函数调用前后自动打印日志,但又不希望修改now()函数的定义,这种在代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator)。
本质上,decorator就是一个返回函数的高阶函数。所以,我们要定义一个能打印日志的decorator,可以定义如下:
In [56]: def log(func): ...: def wrapper(): ...: print('call %s():',func.__name__) ...: return func() ...: return wrapper ...:In [57]: @log ...: def now(): ...: print(my_str) ...:
调用now()函数,不仅会运行now()函数本身,还会在运行now()函数前打印一行日志:
In [58]: now()call %s(): now09:50:25
把@log放到now()函数的定义处,相当于执行了语句:
In [62]: now = log(now)
由于log()是一个decorator,返回一个函数,所以,原来的now()函数仍然存在,只是现在同名的now变量指向了新的函数,于是调用now()将执行新函数,即在log()函数中返回的wrapper()函数。
wrapper()函数的参数定义是(*args, **kw)
,因此,wrapper()函数可以接受任意参数的调用。在wrapper()函数内,首先打印日志,再紧接着调用原始函数。
如果decorator本身需要传入参数,那就需要编写一个返回decorator的高阶函数,写出来会更复杂。比如,要自定义log的文本:
In [67]: def log(text): ...: def decorator(func): ...: def wrapper(): ...: print('{0}{1}:'.format(text,func.__name__)) ...: return func() ...: return wrapper ...: return decorator ...:In [68]: @log('execute') ...: def now(): ...: print(my_str) ...:In [69]: now()executenow:09:50:25
和两层嵌套的decorator相比,3层嵌套的效果是这样的:
In [70]: now = log('execute')(now)In [71]: nowOut[71]: <function __main__.log.<locals>.decorator.<locals>.wrapper>In [72]: now()executewrapper:executenow:09:50:25
我们来剖析上面的语句,首先执行log('execute')
,返回的是decorator函数
,再调用返回的函数,参数是now函数,返回值最终是wrapper函数。
以上两种decorator的定义都没有问题,但还差最后一步。因为我们讲了函数也是对象,它有__name__
等属性,但你去看经过decorator装饰之后的函数,它们的__name__
已经从原来的’now’变成了’wrapper’:
In [73]: now.__name__Out[73]: 'wrapper'
因为返回的那个wrapper()函数名字就是’wrapper’,所以,需要把原始函数的__name__
等属性复制到wrapper()函数中,否则,有些依赖函数签名的代码执行就会出错。
不需要编写wrapper.__name__ = func.__name__
这样的代码,Python内置的functools.wraps
就是干这个事的,所以,一个完整的decorator的写法如下:
In [74]: import functoolsIn [75]: def log(text): ...: def decorator(func): ...: @functools.wraps(func) ...: def wrapper(): ...: print('{0}{1}:'.format(text,func.__name__)) ...: return func() ...: return wrapper ...: return decorator ...:In [76]: def now(): ...: print(my_str) ...:In [77]: now = log('exe')(now)In [78]: nowOut[78]: <function __main__.now>In [79]: now.__name__Out[79]: 'now'In [80]: now()exenow:09:50:25In [81]: @log('exe') ...: def now(): ...: print(my_str) ...:In [82]: now()exenow:09:50:25
- Python 基础 —— 装饰器(1)
- Python——装饰器基础
- python基础——装饰器
- python基础——装饰器
- Python 基础 —— 装饰器(2)
- python基础(06)——装饰器
- python基础----装饰器
- Python 装饰器基础
- python—装饰器
- python—装饰器
- python基础—(高阶,匿名,偏)函数 | 装饰器
- 0基础学Python(6) —— 关于装饰器
- Python基础17--装饰器
- Python基础:13装饰器
- python基础篇--装饰器
- python基础---装饰器模式
- python基础学习-装饰器
- python基础-装饰器进阶
- Redis的30个结合php开发的小实例教程
- 用static关键字修饰类
- 我整理的java开源项目
- Scene
- 移动端判断横屏竖屏
- Python 基础 —— 装饰器(1)
- Retrofit使用一
- Android 电话状态的监听
- static作用(修饰函数、局部变量、全局变量)
- wamp 默认别人机器不能访问自己项目 3.0版本没有直接切换在线状态
- Android各控件Demo下载地址各种ui效果图
- Scheduled注解 定时任务 cron表达式详解
- C++ 获取文件版本
- 特征值分解 & 奇异值分解(SVD)