Python中装饰器学习总结


Posted in Python onFebruary 10, 2018

本文研究的主要内容是Python中装饰器相关学习总结,具体如下。

装饰器(decorator)功能

  • 引入日志
  • 函数执行时间统计
  • 执行函数前预备处理
  • 执行函数后清理功能
  • 权限校验等场景
  • 缓存

装饰器示例

例1:无参数的函数

from time import ctime, sleep

def timefun(func):
 def wrappedfunc():
  print("%s called at %s"%(func.__name__, ctime()))
  func()
 return wrappedfunc

@timefun
def foo():
 print("I am foo")

foo()
sleep(2)
foo()

分析如下:

上面代码理解装饰器执行行为可理解成

foo = timefun(foo)

1,foo先作为参数赋值给func后,foo接收指向timefun返回的wrappedfunc
2,调用foo(),即等价调用wrappedfunc()
3,内部函数wrappedfunc被引用,所以外部函数的func变量(自由变量)并没有释放
4,func里保存的是原foo函数对象

例2:被装饰的函数有参数

from time import ctime, sleep

def timefun(func):
 def wrappedfunc(a, b):
  print("%s called at %s"%(func.__name__, ctime()))
  print(a, b)
  func(a, b)
 return wrappedfunc

@timefun
def foo(a, b):
 print(a+b)

foo(3,5)
sleep(2)
foo(2,4)

例3:被装饰的函数有不定长参数

from time import ctime, sleep

def timefun(func):
 def wrappedfunc(*args, **kwargs):
  print("%s called at %s"%(func.__name__, ctime()))
  func(*args, **kwargs)
 return wrappedfunc

@timefun
def foo(a, b, c):
 print(a+b+c)

foo(3,5,7)
sleep(2)
foo(2,4,9)

例4:装饰器中的return

from time import ctime, sleep

def timefun(func):
 def wrappedfunc():
  print("%s called at %s"%(func.__name__, ctime()))
  func()
 return wrappedfunc

@timefun
def foo():
 print("I am foo")

@timefun
def getInfo():
 return '----hahah---'

foo()
sleep(2)
foo()


print(getInfo())

执行结果:

foo called at Sun Jun 18 00:31:53 2017
I am foo
foo called at Sun Jun 18 00:31:55 2017
I am foo
getInfo called at Sun Jun 18 00:31:55 2017
None

如果修改装饰器为return func(),则运行结果:

foo called at Sun Jun 18 00:34:12 2017
I am foo
foo called at Sun Jun 18 00:34:14 2017
I am foo
getInfo called at Sun Jun 18 00:34:14 2017
----hahah---

小结:一般情况下为了让装饰器更通用,可以有return

例5:装饰器带参数,在原有装饰器的基础上,设置外部变量

from time import ctime, sleep

def timefun_arg(pre="hello"):
 def timefun(func):
  def wrappedfunc():
   print("%s called at %s %s"%(func.__name__, ctime(), pre))
   return func()
  return wrappedfunc
 return timefun

@timefun_arg("itcast")
def foo():
 print("I am foo")

@timefun_arg("python")
def too():
 print("I am too")

foo()
sleep(2)
foo()

too()
sleep(2)
too()
可以理解为

foo()==timefun_arg("itcast")(foo)()

例6:类装饰器

装饰器函数其实是这样一个接口约束,它必须接受一个callable对象作为参数,然后返回一个callable对象。在Python中一般callable对象都是函数,但也有例外。只要某个对象重写了 call() 方法,那么这个对象就是callable的。

class Test():
 def __call__(self):
  print('call me!')

t = Test()
t() # call me
类装饰器demo


class Test(object):
 def __init__(self, func):
  print("---初始化---")
  print("func name is %s"%func.__name__)
  self.__func = func
 def __call__(self):
  print("---装饰器中的功能---")
  self.__func()

说明:

1. 当用Test来装作装饰器对test函数进行装饰的时候,首先会创建Test的实例对象,并且会把test这个函数名当做参数传递到init方法中
即在init方法中的func变量指向了test函数体
2. test函数相当于指向了用Test创建出来的实例对象
3. 当在使用test()进行调用时,就相当于让这个对象(),因此会调用这个对象的call方法
4. 为了能够在call方法中调用原来test指向的函数体,所以在init方法中就需要一个实例属性来保存这个函数体的引用
所以才有了self.func = func这句代码,从而在调用__call方法中能够调用到test之前的函数体

@Test 
def test(): 
print(“—-test—”) 
test() 
showpy()#如果把这句话注释,重新运行程序,依然会看到”?初始化?”

运行结果如下:

---初始化---
func name is test
---装饰器中的功能---
----test---

wraps函数

使用装饰器时,有一些细节需要被注意。例如,被装饰后的函数其实已经是另外一个函数了(函数名等函数属性会发生改变)。

添加后由于函数名和函数的doc发生了改变,对测试结果有一些影响,例如:

def note(func):
 "note function"
 def wrapper():
  "wrapper function"
  print('note something')
  return func()
 return wrapper

@note
def test():
 "test function"
 print('I am test')

test()
print(test.__doc__)

运行结果

note something
I am test
wrapper function

所以,Python的functools包中提供了一个叫wraps的装饰器来消除这样的副作用。例如:

import functools
def note(func):
 "note function"
 @functools.wraps(func)
 def wrapper():
  "wrapper function"
  print('note something')
  return func()
 return wrapper

@note
def test():
 "test function"
 print('I am test')

test()
print(test.__doc__)

运行结果

note something
I am test
test function

总结

以上就是本文关于Python中装饰器学习总结的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站其他相关专题,如有不足之处,欢迎留言指出。感谢朋友们对本站的支持!

Python 相关文章推荐
爬山算法简介和Python实现实例
Apr 26 Python
wxpython中利用线程防止假死的实现方法
Aug 11 Python
python连接mysql实例分享
Oct 09 Python
Python + selenium自动化环境搭建的完整步骤
May 19 Python
Python if语句知识点用法总结
Jun 10 Python
python获取指定字符串中重复模式最高的字符串方法
Jun 29 Python
浅谈利用numpy对矩阵进行归一化处理的方法
Jul 11 Python
实例介绍Python中整型
Feb 11 Python
Pytorch中的variable, tensor与numpy相互转化的方法
Oct 10 Python
Python3实现将一维数组按标准长度分隔为二维数组
Nov 29 Python
详解pandas获取Dataframe元素值的几种方法
Jun 14 Python
Python获取指定日期是"星期几"的6种方法
Mar 13 Python
Python基于hashlib模块的文件MD5一致性加密验证示例
Feb 10 #Python
Python中生成器和迭代器的区别详解
Feb 10 #Python
详解python中的线程
Feb 10 #Python
Odoo中如何生成唯一不重复的序列号详解
Feb 10 #Python
python TCP Socket的粘包和分包的处理详解
Feb 09 #Python
python实现Adapter模式实例代码
Feb 09 #Python
python实现Decorator模式实例代码
Feb 09 #Python
You might like
PHP4实际应用经验篇(7)
2006/10/09 PHP
PHP压缩html网页代码(清除空格,换行符,制表符,注释标记)
2012/04/02 PHP
PHP文件上传小程序 适合初学者学习!
2019/05/23 PHP
PHP面向对象程序设计__tostring()和__invoke()用法分析
2019/06/12 PHP
PHPExcel实现的读取多工作表操作示例
2020/04/14 PHP
js 鼠标点击事件及其它捕获
2009/06/04 Javascript
javascript的动态加载、缓存、更新以及复用(一)
2014/06/09 Javascript
纯js实现div内图片自适应大小(已测试,兼容火狐)
2014/06/16 Javascript
字段太多jquey快速清空表单内容方法
2014/08/21 Javascript
jQuery添加删除DOM元素方法详解
2016/01/18 Javascript
js调用屏幕宽度的简单方法
2016/11/14 Javascript
Swiper实现轮播图效果
2017/07/03 Javascript
vue-router配合ElementUI实现导航的实例
2018/02/11 Javascript
vue富文本框(插入文本、图片、视频)的使用及问题小结
2018/08/17 Javascript
详解Ant Design of React的安装和使用方法
2018/12/27 Javascript
JavaScript 实现HTML DOM增删改查操作的常见方法详解
2020/01/04 Javascript
js实现3D旋转效果
2020/08/18 Javascript
three.js 实现露珠滴落动画效果的示例代码
2021/03/01 Javascript
python使用reportlab实现图片转换成pdf的方法
2015/05/22 Python
python中的闭包函数
2018/02/09 Python
Python中判断输入是否为数字的实现代码
2018/05/26 Python
解决Python正则表达式匹配反斜杠''\''问题
2019/07/17 Python
python代码区分大小写吗
2020/06/17 Python
python 最简单的实现适配器设计模式的示例
2020/06/30 Python
HTML5 实现图片上传预处理功能
2020/02/06 HTML / CSS
Net-A-Porter美国官网:全球时尚奢侈品名站
2017/02/11 全球购物
德国珠宝和手表在线商店:VALMANO
2019/03/24 全球购物
用C#语言写出与SQLSERVER访问时的具体过程
2013/04/16 面试题
合同专员岗位职责
2013/12/18 职场文书
高考寄语大全
2014/04/08 职场文书
祖国在我心中演讲稿500字
2014/05/04 职场文书
食品安全承诺书
2014/05/22 职场文书
信用卡工作证明范本
2015/06/19 职场文书
高三教师工作总结2015
2015/07/21 职场文书
2016年幼儿园教师政治学习心得体会
2016/01/23 职场文书
如何使用Python提取Chrome浏览器保存的密码
2021/06/09 Python