廖雪峰的Python-装饰器
来源:互联网 发布:大数据工程师医疗 编辑:程序博客网 时间:2024/06/05 14:09
一、装饰器(Decorator)
1、定义
在函数运行期间动态的增加函数的功能而又不改变函数的定义的方法叫做装饰器,装饰器的本质是高阶的返回函数。
例1:在函数前做到打印日志的功能。
#!/usr/bin/env python#-*- coding: utf-8 -*-def log(func):def wrapper(*args, **kw): print 'call %s():' % func.__name__ # %s是占位符return func(*args, **kw) # 结束函数wrapper的运行,并将func函数值返回给wrapper。return wrapper # 结束函数log的运行,将函数返回到wrapper。@logdef now():print'2017-07-16'now()
注:由于log()是一个decorator,返回一个函数,所以,原来的now()函数仍然存在,只是现在同名的now变量指向了新的函数,于是调用now()将执行新函数,即在log()函数中返回的wrapper()函数。
wrapper()函数的参数定义是(*args, **kw),因此,wrapper()函数可以接受任意参数的调用。在wrapper()函数内,首先打印日志,再紧接着调用原始函数。
例2:自定义装饰器的文本
#!/usr/bin/env python #-*- coding: utf-8 -*-def log(text):def decorator(func):def wrapper(*args, **kw):print '%s %s():'%(text,func.__name__)return func(*args, **kw)return wrapperreturn decorator@log('execute')def now():print '2017-06-21'now()
注:这样写有一个缺点就是在程序运行完之后,函数的名称改变了,所以,需要把原始函数的__name__等属性复制到wrapper()函数中,否则,有些依赖函数签名的代码执行就会出错。
Python内置的functools.wraps可以实现上述功能,具体使用方法如下。
例3:
#!/usr/bin/env python #-*- coding: utf-8 -*-import functools#导入模块def log(text):def decorator(func):@functools.wraps(func) #调用模块def wrapper(*args, **kw):print '%s %s():'%(text,func.__name__)return func(*args, **kw)return wrapperreturn decorator@log('execute')def now():print '2017-06-21'now()
二、练习题
习题1:请编写一个decorator,能在函数调用的前后打印出'begin call'和'end call'的日志。
#!/usr/env/bin python#-*- coding: utf-8 -*-import functoolsdef log(func): @functools.wraps(func) def wrape(*args,**kw): print 'begin call' func(*args,**kw) print 'end call' return return wrape@logdef now():print '2017年7月10日09:50:45'now()
注:如果按照以前的写法,简单的在return func()后面加上 print ‘end call’程序是不会执行后面的语句的,这里要理解return的含义,即:终止函数的运行,并返回值。
我犯的另一个错误就是,在return后加上 func,导致在返回值的时候再次运行了return 中的函数语句。这个问题的详细解释:https://segmentfault.com/q/1010000010204444?_ea=2203069
习题2:写出一个@log的decorator,使它既支持:
@log
def f():
pass
又支持:
@log('execute')
def f():
pass
#!/usr/bin/env python #-*- coding: utf-8 -*-import functoolsdef log(text): if isinstance(text,str): def decorator(func): @functools.wraps(func) def wrapper(*args,**kw): if text: print'%s %s(): '%(text,func.__name__) else: print'call %s(): '% func.__name__ func(*args,**kw) return return wrapper return decorator else: @functools.wraps(text) def wrapper(*args,**kw): print'call %s(): '%text.__name__ text(*args,**kw) return return wrapper @logdef f1(): print 'testing1' @log('')def f2(): print 'testing2' @log('excute')def f3(): print 'testing3'f1()f2()f3()
同时实现上述两个问题的代码。
#!/usr/bin/env python #-*- coding: utf-8 -*-import functoolsdef log(obj): if isinstance(obj,str): #判断参数obj是否为字符串,若不是,则其为函数参数,执行else内容 #若是字符串,说明其为带参数的decorator def decorator(func): @functools.wraps(func) def wrapper(*args,**kw): print('begin call') #打印函数开始执行信息 if obj: #如果字符串不为空 print('%s %s(): '%(obj,func.__name__)) else: #字符串为空时 print('call %s(): '% func.__name__) func(*args,**kw) #不使用return来返回函数func,而是直接执行,这样可以在该句后面再打印信息 print('end call') #打印函数执行结束信息 return # wrapper函数的返回 return wrapper #decorator函数的返回 return decorator #log函数的返回 else: @functools.wraps(obj) #obj即为函数名称 def wrapper(*args,**kw): print('begin call') print('call %s(): '%obj.__name__) obj(*args,**kw) print('end call') return return wrapper @logdef fnc(): print('I\'m fnc for testing log without parameter') @log('')def fnc2(): print('I\'m fnc2 for testing log with empty parameter') @log('excute')def fnc3(): print('I\'m fnc3 for testing log with parameter') fnc()print('fnc.__name__ = %s' % fnc.__name__)print('----------------------------------')fnc2()print('fnc2.__name__ = %s' % fnc2.__name__)print('----------------------------------')fnc3()print('fnc3.__name__ = %s' % fnc3.__name__)
原文:http://www.cnblogs.com/codingmengmeng/p/5811565.html
2017年7月16日17:38:37
- 廖雪峰的Python-装饰器
- 廖雪峰的Python教程
- 廖雪峰的Python-filter
- 廖雪峰的Git、Python教程
- 廖雪峰的0Python教程
- 廖雪峰的Python教程-网络编程
- 廖雪峰的Python教程-电子邮件
- 廖雪峰的Python教程-生成器
- 廖雪峰的Python-map/reduce
- 廖雪峰的Python—sorted
- 廖雪峰的Python-返回函数
- 廖雪峰的Python-匿名函数-lambda
- Python练习(廖雪峰)
- 廖雪峰python教程
- 廖雪峰python笔记
- Python 学习 廖雪峰
- 读廖雪峰的 Python 教程小结--------Python基础
- 读廖雪峰的 Python 教程小结--------Python函数
- Java开发中的23种设计模式详解
- 聚集索引和非聚集索引(整理)
- 欢迎使用CSDN-markdown编辑器
- javaEE之MVC三层架构及注册登入案例
- 获取单选按钮的值:
- 廖雪峰的Python-装饰器
- 时钟系统
- 关于C语言数组与指针的联系一起
- 2017北大信科夏令营机试B
- 判断页面内容是否存在变动
- Hadoop1.x的伪分布安装步骤
- 【原创】浅谈搜索(下-bfs)
- Bootstrap中jumbotron属性
- UVA 11651 Krypton Number System(矩阵加速DP)