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实现在线程里运行scrapy的方法
Apr 07 Python
python爬虫_自动获取seebug的poc实例
Aug 05 Python
python距离测量的方法
Mar 06 Python
django celery redis使用具体实践
Apr 08 Python
Python 20行简单实现有道在线翻译的详解
May 15 Python
Python程序打包工具py2exe和PyInstaller详解
Jun 28 Python
django自带serializers序列化返回指定字段的方法
Aug 21 Python
python查看数据类型的方法
Oct 12 Python
OpenCV 使用imread()函数读取图片的六种正确姿势
Jul 09 Python
python如何爬取网页中的文字
Jul 28 Python
Python使用eval函数执行动态标表达式过程详解
Oct 17 Python
Python命令行参数定义及需要注意的地方
Nov 30 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
利用 window_onload 实现select默认选择
2006/10/09 PHP
不用mod_rewrite直接用php实现伪静态化页面代码
2008/10/04 PHP
php array_flip() 删除数组重复元素
2009/01/14 PHP
基于simple_html_dom的使用小结
2013/07/01 PHP
Swoole 5将移除自动添加Event::wait()特性详解
2019/07/10 PHP
获取div编辑框,textarea,input text的光标位置 兼容IE,FF和Chrome的方法介绍
2012/11/08 Javascript
关于div自适应高度/左右高度自适应一致的js代码
2013/03/22 Javascript
几种延迟加载JS代码的方法加快网页的访问速度
2013/10/12 Javascript
jquery制作漂亮的弹出层提示消息特效
2014/12/23 Javascript
jquery validate和jquery form 插件组合实现验证表单后AJAX提交
2015/08/26 Javascript
以jQuery中$.Deferred对象为例讲解promise对象是如何处理异步问题
2015/11/13 Javascript
深入浅析Bootstrap列表组组件
2016/05/03 Javascript
JavaScript实现页面跳转的方式汇总
2016/05/16 Javascript
JavaScript实现Fly Bird小游戏
2016/12/15 Javascript
React创建组件的三种方式及其区别
2017/01/12 Javascript
Bootstrap导航条学习使用(一)
2017/02/08 Javascript
详解Vue-基本标签和自定义控件
2017/03/24 Javascript
JS获取鼠标位置距浏览器窗口距离的方法示例
2017/04/11 Javascript
JavaScript通过filereader接口读取文件
2017/05/10 Javascript
简单实现jQuery手风琴效果
2017/08/18 jQuery
Vue安装浏览器开发工具的步骤详解
2019/05/12 Javascript
js实现跟随鼠标移动的小球
2019/08/26 Javascript
Layui实现主窗口和Iframe层参数传递
2019/11/14 Javascript
Python中多线程thread与threading的实现方法
2014/08/18 Python
Pycharm学习教程(7)虚拟机VM的配置教程
2017/05/04 Python
Python带动态参数功能的sqlite工具类
2018/05/26 Python
浅析python 动态库m.so.1.0错误问题
2020/05/09 Python
python和go语言的区别是什么
2020/07/20 Python
HelloFresh奥地利:立即订购烹饪盒
2019/02/22 全球购物
利达恒信公司.NET笔试题面试题
2016/03/05 面试题
电子商务自荐书范文
2014/01/04 职场文书
会计职业生涯规划书
2014/01/13 职场文书
党员公开承诺书范文
2014/03/25 职场文书
建筑公司员工自我鉴定
2014/04/08 职场文书
幼儿园中班下学期评语
2014/04/18 职场文书
幼儿园小班开学寄语(2016秋季)
2015/12/03 职场文书