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 ScrollView 滚动到顶部
有时候使用ScrollView,里边控件比较多的时候,打开界面,会滑到底部,如果要设置滑动到顶部,一般有两种方法 1.使用fullScrol(),scrollView.fullScroll(Scrol ...
- Android RecyclerView 设置item间隔的方法
RecyclerView大家常用,但是如何给加载出来的item增加间隔很多人都不知道,下面是方法,直接上代码了: LinearLayoutManager layoutManager = new Lin ...
- Good Bye 2014 B. New Year Permutation 【传递闭包 贪心】
解题思路:给出一列数an,再给出一个矩阵d[i][j],在满足d[i][j]=1的情况下,称a[i]和a[j]可以交换,问经过交换最后得到字典序最小的数列a[n] 首先是贪心的思想,大的能换就换到后面 ...
- lua_pcall与lua_call之间的区别
lua_pcall与lua_call之间的区别 定义: void lua_call (lua_State *L, int nargs, int nresults); int lua_pcall (lu ...
- SpringBoot学习笔记(1)----环境搭建与Hello World
简介: Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程.该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配 ...
- js指定区域全屏
<html> <head> <title>js指定区域全屏</title> <style> ...
- 在远程X server上显示图形的设置方法
1.在服务器的/etc/ssh/sshd_config中,设置X11Forwarding yes,然后重启ssh服务,cd /etc/init.d这个目录下执行 ./ssh restart 2.在客户 ...
- redis 多实例监控
1.制作redis_low_discovery.sh脚本 mkdir -p /data/service/script/zabbix cd /data/service/script/zabbix cat ...
- groovy : poi 导出 Excel xlsx
參考 file:///poi-3.10-FINAL/docs/spreadsheet/how-to.html#sxssf text2xlsx.groovy 代码例如以下 package xlsx; i ...
- new 对象和Class的getInstance()方法的差别?
创建对象时的差别 1.new 对象包含2步, 1)载入类: 2)而且实例化. 2.Class的对象.getInstance(),只不过实例化. 也就是说.在运行 Class的对象.getInstanc ...