Python装饰器入门学习教程(九步学习)


Posted in Python onJanuary 28, 2016

装饰器(decorator)是一种高级Python语法。装饰器可以对一个函数、方法或者类进行加工。在Python中,我们有多种方法对函数和类进行加工,比如在Python闭包中,我们见到函数对象作为某一个函数的返回结果。相对于其它方式,装饰器语法简单,代码可读性高。因此,装饰器在Python项目中有广泛的应用。

这是在Python学习小组上介绍的内容,现学现卖、多练习是好的学习方式。

第一步:最简单的函数,准备附加额外功能

# -*- coding:gbk -*-
'''示例1: 最简单的函数,表示调用了两次'''
def myfunc():
print("myfunc() called.")
myfunc()
myfunc()

第二步:使用装饰函数在函数执行前和执行后分别附加额外功能

# -*- coding:gbk -*-
'''示例2: 替换函数(装饰)
装饰函数的参数是被装饰的函数对象,返回原函数对象
装饰的实质语句: myfunc = deco(myfunc)'''
def deco(func):
print("before myfunc() called.")
func()
print(" after myfunc() called.")
return func
def myfunc():
print(" myfunc() called.")
myfunc = deco(myfunc)
myfunc()
myfunc()

第三步:使用语法糖@来装饰函数

# -*- coding:gbk -*-
'''示例3: 使用语法糖@来装饰函数,相当于“myfunc = deco(myfunc)”
但发现新函数只在第一次被调用,且原函数多调用了一次'''
def deco(func):
print("before myfunc() called.")
func()
print(" after myfunc() called.")
return func
@deco
def myfunc():
print(" myfunc() called.")
myfunc()
myfunc()

第四步:使用内嵌包装函数来确保每次新函数都被调用

# -*- coding:gbk -*-
'''示例4: 使用内嵌包装函数来确保每次新函数都被调用,
内嵌包装函数的形参和返回值与原函数相同,装饰函数返回内嵌包装函数对象'''
def deco(func):
def _deco():
print("before myfunc() called.")
func()
print(" after myfunc() called.")
# 不需要返回func,实际上应返回原函数的返回值
return _deco
@deco
def myfunc():
print(" myfunc() called.")
return 'ok'
myfunc()
myfunc()

第五步:对带参数的函数进行装饰

# -*- coding:gbk -*-
'''示例5: 对带参数的函数进行装饰,
内嵌包装函数的形参和返回值与原函数相同,装饰函数返回内嵌包装函数对象'''
def deco(func):
def _deco(a, b):
print("before myfunc() called.")
ret = func(a, b)
print(" after myfunc() called. result: %s" % ret)
return ret
return _deco
@deco
def myfunc(a, b):
print(" myfunc(%s,%s) called." % (a, b))
return a + b
myfunc(1, 2)
myfunc(3, 4)

第六步:对参数量不确定的函数进行装饰

# -*- coding:gbk -*-
'''示例6: 对参数数量不确定的函数进行装饰,
参数用(*args, **kwargs),自动适应变参和命名参数'''
def deco(func):
def _deco(*args, **kwargs):
print("before %s called." % func.__name__)
ret = func(*args, **kwargs)
print(" after %s called. result: %s" % (func.__name__, ret))
return ret
return _deco
@deco
def myfunc(a, b):
print(" myfunc(%s,%s) called." % (a, b))
return a+b
@deco
def myfunc2(a, b, c):
print(" myfunc2(%s,%s,%s) called." % (a, b, c))
return a+b+c
myfunc(1, 2)
myfunc(3, 4)
myfunc2(1, 2, 3)
myfunc2(3, 4, 5)

第七步:让装饰器带参数

# -*- coding:gbk -*-
'''示例7: 在示例4的基础上,让装饰器带参数,
和上一示例相比在外层多了一层包装。
装饰函数名实际上应更有意义些'''
def deco(arg):
def _deco(func):
def __deco():
print("before %s called [%s]." % (func.__name__, arg))
func()
print(" after %s called [%s]." % (func.__name__, arg))
return __deco
return _deco
@deco("mymodule")
def myfunc():
print(" myfunc() called.")
@deco("module2")
def myfunc2():
print(" myfunc2() called.")
myfunc()
myfunc2()

第八步:让装饰器带 类 参数

# -*- coding:gbk -*-
'''示例8: 装饰器带类参数'''
class locker:
def __init__(self):
print("locker.__init__() should be not called.")
@staticmethod
def acquire():
print("locker.acquire() called.(这是静态方法)")
@staticmethod
def release():
print(" locker.release() called.(不需要对象实例)")
def deco(cls):
'''cls 必须实现acquire和release静态方法'''
def _deco(func):
def __deco():
print("before %s called [%s]." % (func.__name__, cls))
cls.acquire()
try:
return func()
finally:
cls.release()
return __deco
return _deco
@deco(locker)
def myfunc():
print(" myfunc() called.")
myfunc()
myfunc()

第九步:装饰器带类参数,并分拆公共类到其他py文件中,同时演示了对一个函数应用多个装饰器

# -*- coding:gbk -*-
'''mylocker.py: 公共类 for 示例9.py'''
class mylocker:
def __init__(self):
print("mylocker.__init__() called.")
@staticmethod
def acquire():
print("mylocker.acquire() called.")
@staticmethod
def unlock():
print(" mylocker.unlock() called.")
class lockerex(mylocker):
@staticmethod
def acquire():
print("lockerex.acquire() called.")
@staticmethod
def unlock():
print(" lockerex.unlock() called.")
def lockhelper(cls):
'''cls 必须实现acquire和release静态方法'''
def _deco(func):
def __deco(*args, **kwargs):
print("before %s called." % func.__name__)
cls.acquire()
try:
return func(*args, **kwargs)
finally:
cls.unlock()
return __deco
return _deco 
# -*- coding:gbk -*-

'''示例9: 装饰器带类参数,并分拆公共类到其他py文件中

同时演示了对一个函数应用多个装饰器'''

from mylocker import *
class example:
@lockhelper(mylocker)
def myfunc(self):
print(" myfunc() called.")
@lockhelper(mylocker)
@lockhelper(lockerex)
def myfunc2(self, a, b):
print(" myfunc2() called.")
return a + b
if __name__=="__main__":
a = example()
a.myfunc()
print(a.myfunc())
print(a.myfunc2(1, 2))
print(a.myfunc2(3, 4))

以上给大家分享了Python装饰器入门学习教程(九步学习),希望对大家有所帮助。

Python 相关文章推荐
python实现爬取千万淘宝商品的方法
Jun 30 Python
python实现kNN算法
Dec 20 Python
python版微信跳一跳游戏辅助
Jan 11 Python
Django框架实现的简单分页功能示例
Dec 04 Python
Python3.7 dataclass使用指南小结
Feb 22 Python
浅谈Python大神都是这样处理XML文件的
May 31 Python
python 利用turtle库绘制笑脸和哭脸的例子
Nov 23 Python
Python如何转换字符串大小写
Jun 04 Python
python 如何利用argparse解析命令行参数
Sep 11 Python
如何使用python-opencv批量生成带噪点噪线的数字验证码
Dec 21 Python
pycharm配置QtDesigner的超详细方法
Jan 25 Python
Python用requests库爬取返回为空的解决办法
Feb 21 Python
基于Python如何使用AIML搭建聊天机器人
Jan 27 #Python
使用Python写个小监控
Jan 27 #Python
基于Python实现通过微信搜索功能查看谁把你删除了
Jan 27 #Python
Python图像灰度变换及图像数组操作
Jan 27 #Python
让python在hadoop上跑起来
Jan 27 #Python
CentOS安装pillow报错的解决方法
Jan 27 #Python
python实现文本去重且不打乱原本顺序
Jan 26 #Python
You might like
ob_start(),ob_start('ob_gzhandler')使用
2006/12/25 PHP
php解决约瑟夫环示例
2014/04/09 PHP
smarty中常用方法实例总结
2015/08/07 PHP
写了一个layout,拖动条连贯,内容区可为iframe
2007/08/19 Javascript
让浏览器非阻塞加载javascript的几种方法小结
2011/04/25 Javascript
JavaScript判断DOM何时加载完毕的技巧
2012/11/11 Javascript
JQuery包裹DOM节点的方法
2015/06/11 Javascript
每天一篇javascript学习小结(Date对象)
2015/11/13 Javascript
跟我学习javascript的闭包
2015/11/16 Javascript
js实现不重复导入的方法
2016/03/02 Javascript
Angular 页面跳转时传参问题
2016/08/01 Javascript
利用Angularjs实现幻灯片效果
2016/09/07 Javascript
谈谈Vue.js——vue-resource全攻略
2017/01/16 Javascript
Vue.js实战之组件的进阶
2017/04/04 Javascript
elemetUi 组件--el-upload实现上传Excel文件的实例
2017/10/27 Javascript
浅谈ajax在jquery中的请求和servlet中的响应
2018/01/22 jQuery
js保留两位小数方法总结
2018/01/31 Javascript
基于vue中css预加载使用sass的配置方式详解
2018/03/13 Javascript
Vue实现自定义下拉菜单功能
2018/07/16 Javascript
jQuery实现的点击显示隐藏下拉菜单功能完整示例
2019/05/17 jQuery
浅谈Vue使用Elementui修改默认的最快方法
2020/12/05 Vue.js
python遍历类中所有成员的方法
2015/03/18 Python
详细讲解Python中的文件I/O操作
2015/05/24 Python
深入理解Django自定义信号(signals)
2018/10/15 Python
python判断字符串或者集合是否为空的实例
2019/01/23 Python
Osklen官方在线商店:巴西服装品牌
2019/04/25 全球购物
小米官方旗舰店:Xiaomi
2020/08/07 全球购物
外贸公司实习自我鉴定
2013/09/24 职场文书
《第一朵杏花》教学反思
2014/04/16 职场文书
班主任对学生的评语
2014/04/26 职场文书
2016新年慰问信范文
2015/03/25 职场文书
2015年护理工作总结范文
2015/04/03 职场文书
银行反洗钱宣传活动总结
2015/05/08 职场文书
2015小学新教师个人工作总结
2015/10/14 职场文书
高中班长竞选稿
2015/11/20 职场文书
学校教代会开幕词
2016/03/04 职场文书