python中的装饰器decorator
python中的装饰器
装饰器是为了解决以下描述的问题而产生的方法
我们在已有的函数代码的基础上,想要动态的为这个函数增加功能而又不改变原函数的代码
例如有三个函数:
def f1(x):
return x
def f2(x):
return x*x
def f3(x):
return x*x*x
而我们想为这三个函数增加一个函数调用打印功能 类似print("call f1()")
如果我们直接修改的话,需要对每个函数的内部进行改写。
所以为了简化代码,我们可以使用python内置的@装饰器的方法,可以做到修饰函数的功能
Python的 decorator 本质上就是一个高阶函数,它接收一个函数作为参数,然后,返回一个新函数。
装饰器可以极大地简化代码,避免每个函数写重复性代码
不带参数的decorator
例如我们可以编写一个@log可以打印函数调用的装饰器
def log(f):
def fn(x):
print ('call ' + f.__name__ + '()...')
return f(x)
return fn
然后我们可以测试一下
@log
def f1(x):
return x a=f1(1)
print(a)
结果
call f1()...
1
但是,对于参数不是一个的函数,调用将报错:
@log
def add(x, y):
return x + y
print (add(1, 2))
Traceback (most recent call last):
File "D:/pythonwork/cvworktest/final/practice.py", line 12, in <module>
print (add(1, 2))
TypeError: fn() takes 1 positional argument but 2 were given
这是因为add() 函数需要传入两个参数,但是 @log 写死了只含一个参数的返回函数。
要让 @log 自适应任何参数定义的函数,可以利用Python的 *args 和 **kw,保证任意个数的参数总是能正常调用:
def log(f):
def fn(*args, **kw):
print ('call ' + f.__name__ + '()...')
return f(*args, **kw)
return fn
现在,对于任意函数,@log 都能正常工作。
带参数decorator
上面的@log不带任何参数,同样我们可以编写一个带参数的decorator
例如如果有的函数非常重要,希望打印出'[INFO] call xxx()...',有的函数不太重要,希望打印出'[DEBUG] call xxx()...',这时
log函数本身就需要传入'INFO'或'DEBUG'这样的参数,类似这样:
@log('DEBUG')
def my_func():
pass
我们把它翻译成高阶函数就是这样:
my_func = log('DEBUG')(my_func)
展开:
log_decorator = log('DEBUG')
my_func = log_decorator(my_func)
又相当于:
log_decorator = log('DEBUG')
@log_decorator
def my_func():
pass
所以,带参数的log函数首先返回一个decorator函数,再让这个decorator函数接收my_func并返回新函数:
def log(content):
def log_decorator(f):
def fn(*args, **kw):
print ('[%s] %s()...' % (content, f.__name__))
return f(*args, **kw)
return fn
return log_decorator @log('DEBUG')
def test():
pass
print (test())
结果:
[DEBUG] test()...
None
decorator的注意事项:
经过@decorator“改造”后的函数,和原函数相比,除了功能多一点外,还有很重要的一点就是函数自身的改变
在没有decorator的情况下,打印函数名:
def f1(x):
pass
print (f1.__name__)
结果:
f1
有decorator的情况下,再打印函数名:
def log(f):
def wrapper(*args, **kw):
print ('call...')
return f(*args, **kw)
return wrapper
@log
def f2(x):
pass
print (f2.__name__)
结果:
wrapper
由于decorator返回的新函数函数名已经不是'f2',而是@log内部定义的'wrapper'。这对于那些依赖函数名的代码就会失效。decorator还改变了函数的__doc__等其它属性。如果要让调用者看不出一个函数经过了@decorator的“改造”,就需要把原函数的一些属性复制到新函数中:
def log(f):
def wrapper(*args, **kw):
print ('call...')
return f(*args, **kw)
wrapper.__name__ = f.__name__
wrapper.__doc__ = f.__doc__
return wrapper
这样写decorator很不方便,因为我们也很难把原函数的所有必要属性都一个一个复制到新函数上,所以Python内置的functools可以用来自动化完成这个“复制”的任务:
import functools
def log(f):
@functools.wraps(f)
def wrapper(*args, **kw):
print ('call...')
return f(*args, **kw)
return wrapper
注意:对于函数的参数信息哦我们无法确定,因为装饰器与原函数的参数名不一定一样
python中的装饰器decorator的更多相关文章
- 浅析python中的装饰器decorator
最近学习python,其中decorator比较难理解,遂写一篇来总结供后续查阅. 定义一个函数,想在运行时动态的改变函数的功能,又不想改变函数本身的代码,可以使用高阶函数(可以使用函数作为参数) 装 ...
- [转] Python中的装饰器(decorator)
想理解Python的decorator首先要知道在Python中函数也是一个对象,所以你可以 将函数复制给变量 将函数当做参数 返回一个函数 函数在Python中和变量的用法一样也是一等公民,也就是高 ...
- 简单说明Python中的装饰器的用法
简单说明Python中的装饰器的用法 这篇文章主要简单说明了Python中的装饰器的用法,装饰器在Python的进阶学习中非常重要,示例代码基于Python2.x,需要的朋友可以参考下 装饰器对与 ...
- 写python中的装饰器
python中的装饰器主要用于在已有函数实现功能前附加需要输出的信息,下面将用实例展示我如何写装饰器. 首先分别尝试写装饰器装饰一个无参函数和一个有参函数(被装饰函数仅输出,无返回值情况下) def ...
- 【Python】python中的装饰器——@
对装饰器本来就一知半解的,今天终于弄清楚了,Python中的装饰器是对装饰者模式的很好运用,简化到骨子里了. python中为什么需要装饰器,看这里:http://www.cnblogs.com/hu ...
- Python 中实现装饰器时使用 @functools.wraps 的理由
Python 中使用装饰器对在运行期对函数进行一些外部功能的扩展.但是在使用过程中,由于装饰器的加入导致解释器认为函数本身发生了改变,在某些情况下——比如测试时——会导致一些问题.Python 通过 ...
- python中@property装饰器的使用
目录 python中@property装饰器的使用 1.引出问题 2.初步改善 3.使用@property 4.解析@property 5.总结 python中@property装饰器的使用 1.引出 ...
- python语法32[装饰器decorator](转)
一 装饰器decorator decorator设计模式允许动态地对现有的对象或函数包装以至于修改现有的职责和行为,简单地讲用来动态地扩展现有的功能.其实也就是其他语言中的AOP的概念,将对象或函数的 ...
- python 语法之 装饰器decorator
装饰器 decorator 或者称为包装器,是对函数的一种包装. 它能使函数的功能得到扩充,而同时不用修改函数本身的代码. 它能够增加函数执行前.执行后的行为,而不需对调用函数的代码做任何改变. 下面 ...
随机推荐
- (转载) android项目大全,总有你所需的
目录视图 摘要视图 订阅 赠书 | 异步2周年,技术图书免费选 程序员8月书讯 项目管理+代码托管+文档协作,开发更流畅 [置顶] android项目大全,总有你所需的 标签: 源 ...
- 向Vue实例混入plusready
(function () { var onPlusReady = function (callback, context = this) { if (window.plus) { callback.c ...
- 创建一个 Django 项目
一. 创建项目 其中: 确认项目是否创建成功: 在 manage.py 目录上运行 python manage.py runserver server 启动后,在浏览器访问 http://127.0. ...
- 【BZOJ2006】【NOI2010】超级钢琴
题意: Description 小Z是一个小有名气的钢琴家,最近C博士送给了小Z一架超级钢琴,小Z希望能够用这架钢琴创作出世界上最美妙的音乐. 这架超级钢琴可以弹奏出n个音符,编号为1至n.第i个音符 ...
- 紫书 习题 11-7 UVa 10801 (单源最短路变形)
把每个电梯口看作一个节点, 然后计算边的权值的时候处理一下, 就ok了. #include<cstdio> #include<vector> #include<queue ...
- 【codeforces 816C】Karen and Game
[题目链接]:http://codeforces.com/contest/816/problem/C [题意] 给你一个n*m的矩阵; 一开始所有数字都是0; 每次操作,你能把某一行,或某一列的数字全 ...
- Echache整合Spring缓存实例讲解
摘要:本文主要介绍了EhCache,并通过整合Spring给出了一个使用实例. 一.EhCache 介绍 EhCache 是一个纯Java的进程内缓存框架,具有快速.精干等特点,是Hibernate中 ...
- windows 下面的grep awk 命令
windows 下面的grep awk 命令 grep 学习了:http://blog.csdn.net/chengfans/article/details/53784936 awk学习了:http: ...
- 图像切割—基于图的图像切割(Graph-Based Image Segmentation)
图像切割-基于图的图像切割(Graph-Based Image Segmentation) Reference: Efficient Graph-Based Image Segmentation ...
- hdu_4430,二分
注意处理溢出 #include<iostream> #include<cstdio> #include<cstring> #include<algorithm ...