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创建只读属性对象的方法(ReadOnlyObject)
Feb 10 Python
Python正则表达式常用函数总结
Jun 24 Python
Python中类的初始化特殊方法
Dec 01 Python
使用python爬取B站千万级数据
Jun 08 Python
python抓取网页内容并进行语音播报的方法
Dec 24 Python
python 使用while写猜年龄小游戏过程解析
Oct 07 Python
Python生成验证码、计算具体日期是一年中的第几天实例代码详解
Oct 16 Python
详解Python中打乱列表顺序random.shuffle()的使用方法
Nov 11 Python
在Python中使用MongoEngine操作数据库教程实例
Dec 03 Python
django数据模型(Model)的字段类型解析
Dec 25 Python
解决Python中导入自己写的类,被划红线,但不影响执行的问题
Jul 13 Python
python小技巧——将变量保存在本地及读取
Nov 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
php5.2以下版本无json_decode函数的解决方法
2014/05/25 PHP
php格式化时间戳
2016/12/17 PHP
PHP判断密码强度的方法详解
2017/05/26 PHP
PHP+mysql实现的三级联动菜单功能示例
2019/02/15 PHP
在laravel框架中使用model层的方法
2019/10/08 PHP
基于jquery ajax 用户无刷新登录方法详解
2012/04/28 Javascript
jquery使整个div区域可以点击的方法
2015/06/24 Javascript
基于JavaScript代码实现微信扫一扫下载APP
2015/12/30 Javascript
详解如何在Vue2中实现组件props双向绑定
2017/03/29 Javascript
vue.js中mint-ui框架的使用方法
2017/05/12 Javascript
AngularJS 异步解决实现方法
2017/06/12 Javascript
Easy UI动态树点击文字实现展开关闭功能
2017/09/30 Javascript
React BootStrap用户体验框架快速上手
2018/03/06 Javascript
JavaScript获取移动设备型号的实现代码(JS获取手机型号和系统)
2018/03/10 Javascript
vue实现多个元素或多个组件之间动画效果
2018/09/25 Javascript
浅谈在不使用ssr的情况下解决Vue单页面SEO问题(2)
2018/11/08 Javascript
后台使用freeMarker和前端使用vue的方法及遇到的问题
2019/06/13 Javascript
js+springMVC 提交数组数据到后台的实例
2019/09/21 Javascript
vue实现简易图片左右旋转,上一张,下一张组件案例
2020/07/31 Javascript
详解Python中的各种函数的使用
2015/05/24 Python
python下调用pytesseract识别某网站验证码的实现方法
2016/06/06 Python
python中使用PIL制作并验证图片验证码
2018/03/15 Python
wxPython实现整点报时
2019/11/18 Python
SHEIN香港:价格实惠的女性时尚服装
2018/08/14 全球购物
英国HYPE双肩包官网:英国本土时尚潮牌
2018/09/26 全球购物
马来西亚与新加坡长途巴士售票网站:BusOnlineTicket.com
2018/11/05 全球购物
eDreams加拿大:廉价航班、酒店和度假
2019/03/29 全球购物
写好求职应聘自荐信的三部曲
2013/09/21 职场文书
自我鉴定思想方面
2013/10/07 职场文书
《花的勇气》教后反思
2014/02/12 职场文书
六年级学生评语
2014/04/22 职场文书
放飞理想演讲稿
2014/09/09 职场文书
农村文化建设标语
2014/10/07 职场文书
咖啡厅里的创业计划书
2019/08/21 职场文书
python基础学习之生成器与文件系统知识总结
2021/05/25 Python
vue router 动态路由清除方式
2022/05/25 Vue.js