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 View 上下左右四种间距的设置方法
RecyclerView控件大家肯定不陌生,已经应用有一段时间了,最近在项目中写一个GridLayout样式的RecyclerView时需要设置,item之间左右的间距,下面是我总结的一个设置间距的方 ...
- 字符串格式化输出、while循环、运算符、编码
1.字符串格式化输出 %占位符: %s => 字符串 %d=>整数型 %%=>转义 普通的% %()不能多,不能少,一一对应 f"{}"大括号里的内容一般都放变量 ...
- GCD - Extreme (II) UVA - 11426 欧拉函数_数学推导
Code: #include<cstdio> using namespace std; const int maxn=4000005; const int R=4000002; const ...
- 路飞学城Python-Day14
转载:python之路-路飞学城-python-book [25.常用模块-logging模块详解] [26.常用模块-logging模块详解2] [27.常用模块-logging模块日志过滤和日志文 ...
- selenium自动化(一).........................................搭建环境
一 环境搭建 安装python(建议使用py3) py2和py3在语法上会有一定的差别 第三方插件逐步转向py3,很多py2的插件已经停止维护 本教程的所有代码基于py3 安装selenium插件 ...
- Qt之QSS(语法高亮)
简述 语法高亮是文本编辑器用来显示文本的,特别是源代码,根据不同的类别来用不同的颜色和字体显示.这个功能有助于编写结构化的语言,例如:编程语言.标记语言,这些语言的语法错误显示是有区别的. 简述 详细 ...
- Android开发学习之事件处理和Button具体解释
Android的事件处理机制: 1.基于监听器的事件处理 --- 组件绑定特定的事件监听器 --- 重点 2.基于回调的事件处理 --- 主要做法是重写Android组件特定的回调函数, ...
- Hdu4786
Fibonacci Tree Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) T ...
- .Net配置虚拟域名
1.在IIS中配置和地址端口,和名称. 2.在hosts文件中加上地址匹配. 3.重启IIS管理网站. 就可以通过虚拟域名进行访问了.
- IPS
转自:http://www.ithome.com.tw/node/79293 企業中網路環境的防護,通常都是先有防火牆,再搭配IPS.但是,實際上買得起IPS防護的企業有限,這是因為IPS的價格很昂貴 ...