内容简介:装饰器是可调用的对象,其参数是另一个函数(被装饰的函数)。python的世界中,一切皆对象,把函数看做一个对象,一个可以拼接、编辑的对象。执行对象的方法是__ 对象()__观察下面的两个调用,他们的效果是一样的。
装饰器是可调用的对象,其参数是另一个函数(被装饰的函数)。python的世界中,一切皆对象,把函数看做一个对象,一个可以拼接、编辑的对象。执行对象的方法是__ 对象()__
装饰器只是 python 的语法糖
观察下面的两个调用,他们的效果是一样的。
#!/usr/bin/env python #-*-coding:utf-8-*- ''' @file: dec4.py @time: 2018/12/13 17:15 ''' import functools def register(func): @functools.wraps(func) def warpper(*args,**kwargs): print("啦啦啦,这里装饰函数 %s"%func.__name__) result = func() #这里就是真正的执行逻辑 return result return warpper # 返回包装后的函数 @register def f1(): print("使用@语法的装饰器 %s"%f1.__name__) def f2(): print("没@语法的装饰器 %s" % f2.__name__) if __name__ == '__main__': f1() register(f2)() #或者 # f_ = register(f2) # f_() 复制代码
装饰器启动装饰的时机
1、文件导入时装饰器已经启动对函数的装饰。
装饰器的一个关键特性是,它们在被装饰的函数定义之后立即运行。 这通常是在导入时(即 Python 加载模块时)。-- cookbook
创建文件 dec1.py
# dec1.py registry = [] # 存放注册函数 def register(func): print('装饰器入列表(%s)' % func.__name__) registry.append(func) return func @register def f1(): print('执行 %s'%f1.__name__) @register def f2(): print('执行 %s' % f2.__name__) 复制代码
创建文件 dec2.py
# dec2.py from 你的目录 import dec1 复制代码
执行文件 dec2.py 输出如下:
装饰器返回的结果
1、返回目标函数。 2、返回目标函数的结果。
以上 register的用法适用于对函数进行预处理的场景,例如flask框架的路由注册,在flask app启动时将所有的函数收集起来,与注册的路径进行一一对应,但是函数运行时跟原函数没有任何区别,因为装饰器返回的还是目标函数。假如我们需要在函数运行时进行日志的输出,则需要将函数进行一层封装,即将目标函数包装成另一个函数,这时返回的是另一个函数,只是包装后的函数可以进行额外的操作。
以下是两个装饰器的写法,注意区别。
import functools def register1(func): #在文件引入时返回目标函数的装饰器 #这里进行一些函数预处理的操作,例如将函数名字收集进一个列表 #list.append(func.__name__) return func def register2(func): #在函数运行时返回函数的装饰器 @functools.wraps(func) def warpper(*args,**kwargs): print("函数没有执行 %s"%func.__name__) result = func #这里就是真正的执行逻辑 #注意-----这里没有执行函数 return result return warpper # 返回包装后的函数 def register3(func): #返回目标函数结果的装饰器 @functools.wraps(func) def warpper(*args,**kwargs): print("函数开始执行 %s"%func.__name__) result = func() #这里就是真正的执行逻辑 return result return warpper # 返回包装后的函数 @register1 def f1(): print("执行函数 %s"%f1.__name__) @register2 def f2(): print("执行函数 %s"%f2.__name__) @register3 def f3(): print("执行函数 %s"%f3.__name__) if __name__ == '__main__': f1() f2() f3() 复制代码
执行结果:
这时添加代码:
if __name__ == '__main__': f1() f2() f_ = f2() print("开始真正执行f2函数啦") f_() f3() 复制代码
执行结果:
装饰函数的属性保持
1、使用@functools.wraps
你会发现下面的代码中,如果wrapper函数没有使用__@functools.wraps装饰__的话,f1.__name__返回的是wrapper函数的名字,这是因为我们返回的函数已经是wrapper这个函数,所以__name__属性也就不是原来函数的了,__@functools.wraps装饰器__的作用就是将目标函数的属性例如__name__等原封不动转移给包装好的函数。
#!/usr/bin/env python #-*-coding:utf-8-*- ''' @file: dec4.py @time: 2018/12/13 17:15 ''' import functools def register(func): #返回目标函数结果的装饰器 def warpper(*args,**kwargs): result = func() #这里就是真正的执行逻辑 return result return warpper # 返回包装后的函数 def register2(func): #返回目标函数结果的装饰器 @functools.wraps(func) def warpper(*args,**kwargs): result = func() #这里就是真正的执行逻辑 return result return warpper # 返回包装后的函数 @register def f1(): print("函数名为 %s"%f1.__name__) @register2 def f2(): print("函数名为 %s" % f2.__name__) if __name__ == '__main__': f1() f2() #或者 #f_ = register(f2) #f_() 复制代码
带参数的装饰器
1、外层嵌套一层函数传参,返回一个装饰器。
装饰器也是一个对象,只要使用一个函数封装装饰器,返回目标装饰器即可,这时就可以通过外层的函数传进参数。
#!/usr/bin/env python # -*-coding:utf-8-*- ''' @author: 黄伟文 @email: huangweiwen@wtoip.com @file: dec5.py @time: 2018/12/13 18:13 ''' import functools def dec_arg(arg=None): def register(func): @functools.wraps(func) def wrapper(*args, **kwargs): print('传进的参数为 %s' % arg) return func(*args, **kwargs) return wrapper return register #这是装饰器 @dec_arg(arg='aaaa') def f1(): print("执行 %s"%f1.__name__) def f2(): print("执行 %s" % f2.__name__) if __name__ == '__main__': f1() f2_ = dec_arg(arg='bbbb')(f2) f2_() dec_arg(arg='cccc')(f2)() 复制代码
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
计算机动画算法与编程基础
雍俊海 / 清华大学出版社 / 2008-7 / 29.00元
《计算机动画算法与编程基础》整理了现有动画算法和编程的资料,提取其中基础的部分,结合作者及同事和学生的各种实践经验,力求使得所介绍的动画算法和编程方法更加容易理解,从而让更多的人能够了解计算机动画,并进行计算机动画算法设计和编程实践。《计算机动画算法与编程基础》共8章,内容包括:计算机动画图形和数学基础知识,OpenGL动画编程方法,关键帧动画和变体技术,自由变形方法,粒子系统和关节动画等。一起来看看 《计算机动画算法与编程基础》 这本书的介绍吧!