Python学习笔记(12)-装饰器详解
2017-01-16 23:57
627 查看
之前在笔记(11)中,简单写了装饰器的用法,看了廖老师的教程感觉头大了不少,老纠结
结果:
结果:
结果:
结果:log处并没有调用,所以一共输出2次
结果:
因为自定义的函数参数类型和个数不确定,所以根据之前函数参数的笔记(7),可以将任意函数参数表示成
此时不论其他函数多少个参数,都会按照装饰器的逻辑在函数执行前后加上log语句
结果:
e.g. 同时兼容
代码:
结果:
return到底要不要,又网上搜集许多讲解,现分步骤详细描述下一个常规的装饰器的写法。不足之处今后再补充。(日志的打印格式我是手动改的,为了看着舒服额已→_→)
1.最简单的输出时间的函数
代码:(就是简单的输出字符串)def myfun(): print('├2017-01-16┤') myfun()
结果:
├2017-01-16┤
2.使用装饰器,在输出的前后各加上log日志
代码:(简单的使用装饰器)def log(fun): print('┌--before--┐') fun() # 此处调用传进来的函数 print('└--after---┘') def myfun(): print('├2017-01-16┤') myfun = log(myfun) # 将函数传递给log函数,再用变量myfun指向它 print(myfun) # 此时的myfun没指向任何内存地址,因为log函数没有返回值
结果:
┌--before--┐
├2017-01-16┤└--after---┘
None
3.利用Python的@语句
代码:(使用@语法,吧
decorator放在函数的定义的地方)
def log(fun): print('┌--before--┐') fun() print('└--after---┘') @log # 只在此处添加了@log 此句相当于 myfun = log(myfun) def myfun(): print('├2017-01-16┤') # myfun = log(myfun) print(myfun) # 仍旧没有指向内存地址
结果:
┌--before--┐
├2017-01-16┤└--after---┘
None
4.以上的写法只能调用一次,若要多次调用,则需要在装饰器内定义包装函数
代码:(log内定义包装函数,并将此函数返回)def log(fun): def cover(): # 定义包装函数 print('┌--before--┐') fun() print('└--after---┘') return cover # 将包装函数返回,注意返回的是函数名(即变量),不是调用函数cover() @log # 此时 myfun = log(myfun) 中,myfun指向了cover,但是并没有调用,和第3步直接调用不同 def myfun(): print('├2017-01-16┤') print(myfun) # myfun已经指向了cover myfun() myfun() # 可调用多次
结果:log处并没有调用,所以一共输出2次
<function log.<locals>.cover at 0x0000000000BCDD08>
┌--before--┐
├2017-01-16┤└--after---┘
┌--before--┐
├2017-01-16┤└--after---┘
5.自定义函数中带有参数和返回值
代码:(只是将包装函数增加参数)def log(fun): def cover(a, b): # 此处的参数需要和原函数参数相同 print('┌--before--┐') result = fun(a, b) # 调用函数后,将结果赋值给result变量 print('└--after---┘') return result # 此时可返回结果 return cover @log def myfun(a, b): print('├2017-01-16┤') return a * b print(myfun) print(myfun(3, 6)) # 函数结果已经返回 print(myfun(6, 9))
结果:
<function log.<locals>.cover at 0x000000000073DD08>
┌--before--┐
├2017-01-16┤└--after---┘
18
┌--before--┐
├2017-01-16┤└--after---┘
54
因为自定义的函数参数类型和个数不确定,所以根据之前函数参数的笔记(7),可以将任意函数参数表示成
func(*args, **kw),所以上述代码
cover函数的定义可以改为
def cover(*args, **kwargs): # 此处的参数需要和原函数参数相同 print('┌--before--┐') result = fun(*args, **kwargs) print('└--after---┘') return result
此时不论其他函数多少个参数,都会按照装饰器的逻辑在函数执行前后加上log语句
6.装饰器携带参数的情况
代码:(比如,自定义log文本内容(装饰器外控制))def log(message): # log传入的参数变为14行传入的参数 def deco(fun): # 参数fun是原函数 def cover(*args, **kwargs): print('┌--%s--┐' % message) # 使用传入的参数message打印日志 result = fun(*args, **kwargs) print('└--%s--┘' % message) return result return cover return deco @log('my message') # 此句相当于 myfun = log('my message')(myfun) def myfun(a, b): print('├--2017-01-16--┤') return a * b print(myfun) print(myfun(3, 6)) print(myfun(6, 9))
结果:
<function log.<locals>.deco.<locals>.cover at 0x00000000011CDD90> ┌--my message--┐ ├--2017-01-16--┤ └--my message--┘ 18 ┌--my message--┐ ├--2017-01-16--┤ └--my message--┘ 54
e.g. 同时兼容
log和
log('sth')
代码:
def log(message): # log传入的参数变为14行传入的参数 def deco(fun, msg=message): # 参数fun是原函数 def cover(*args, **kwargs): print('┌--%s--┐' % msg) # 使用传入的参数打印日志 result = fun(*args, **kwargs) print('└--%s--┘' % msg) return result return cover if isinstance(message, str): # 是字符串的情况下,正常执行 return deco else: return deco(message, '---') # 不是字符串或者为空等的情况,此时的message是传过来的函数,调用deco(),返回变量指向cover函数 @log('my message') # 此句相当于 myfun = log('my message')(myfun) def myfun(a, b): print('├--2017-01-16--┤') return a * b @log def myfun2(): print('├-other-┤') myfun(1, 2) myfun2()
结果:
┌--my message--┐ ├--2017-01-16--┤ └--my message--┘ ┌-------┐ ├-other-┤ └-------┘
相关文章推荐
- python 学习笔记(12)序列化python 对象
- python学习笔记:字典的使用示例详解
- python 学习笔记 metaclass详解
- Python装饰器学习笔记
- Python学习笔记(2)装饰器
- Python学习笔记之疑问12:什么是tuple
- python装饰器的学习笔记二
- Python学习笔记12:标准库之对象序列化(pickle包,cPickle包)
- python学习笔记-(12)python中模块的概念
- Python学习笔记:详解random模块和time模块
- python 学习笔记12-----网络编程
- Python学习笔记5:函数参数详解
- python基础教程_学习笔记12:充电时刻——模块
- Python 学习笔记12
- FreeBSD学习笔记12-pureftpd使用详解(1)-安装、配置、实现匿名登录
- Python装饰器学习笔记
- python学习笔记12--函数
- Python开发技术详解 学习笔记
- python学习笔记12(函数三): 参数类型、递归、lambda函数
- python学习笔记四 迭代器,生成器,装饰器(基础篇)