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中正则表达式的用法实例汇总
Aug 18 Python
python基础教程之常用运算符
Aug 29 Python
使用Python内置的模块与函数进行不同进制的数的转换
Mar 12 Python
python使用matplotlib绘制柱状图教程
Feb 08 Python
浅谈Python用QQ邮箱发送邮件时授权码的问题
Jan 29 Python
简单实现python聊天程序
Apr 01 Python
Pytorch加载部分预训练模型的参数实例
Aug 18 Python
python 通过视频url获取视频的宽高方式
Dec 10 Python
Python实现自动访问网页的例子
Feb 21 Python
python plt可视化——打印特殊符号和制作图例代码
Apr 17 Python
Python内置异常类型全面汇总
May 28 Python
Python猫眼电影最近上映的电影票房信息
Sep 18 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
2019年漫画销量排行榜:鬼灭登顶 海贼单卷制霸 尾田盛赞鬼灭
2020/03/08 日漫
老照片 - 几十年前的收音机与人
2021/03/02 无线电
php加密解密函数authcode的用法详细解析
2013/10/28 PHP
php编程实现简单的网页版计算器功能示例
2017/04/26 PHP
基于jquery的获取浏览器窗口大小的代码
2011/03/28 Javascript
轻松创建nodejs服务器(4):路由
2014/12/18 NodeJs
JavaScript中的replace()方法使用详解
2015/06/06 Javascript
关于javascript中dataset的问题小结
2015/11/16 Javascript
jquery树形菜单效果的简单实例
2016/06/06 Javascript
简单实现js间歇或无缝滚动效果
2016/06/29 Javascript
Node.js中文件操作模块File System的详细介绍
2017/01/05 Javascript
在vue-cli脚手架中配置一个vue-router前端路由
2017/07/03 Javascript
使用JS动态显示文本
2017/09/09 Javascript
解决Layui选择全部,换页checkbox复选框重新勾选的问题方法
2018/08/14 Javascript
JavaScript禁用右键单击优缺点分析
2019/01/20 Javascript
详解vuex数据传输的两种方式及this.$store undefined的解决办法
2019/08/26 Javascript
如何在vue项目中嵌入jsp页面的方法(2种)
2020/02/06 Javascript
python判断、获取一张图片主色调的2个实例
2014/04/10 Python
python制作websocket服务器实例分享
2016/11/20 Python
Python字符串hashlib加密模块使用案例
2020/03/10 Python
CSS3 @font-face属性使用指南
2014/12/12 HTML / CSS
Qoo10马来西亚:全球时尚和引领潮流的购物市场
2016/08/25 全球购物
哥伦比亚最大的网上商店:Linio哥伦比亚
2016/09/25 全球购物
稀有和绝版书籍:Biblio.com
2017/02/02 全球购物
Sunglasses Shop丹麦:欧洲第一的太阳镜在线销售网站
2017/10/22 全球购物
Electric官网:美国高级眼镜和配件品牌
2020/06/04 全球购物
Happy Plugs官网:瑞典无线耳机品牌
2020/07/16 全球购物
八皇后问题,输出了所有情况,不过有些结果只是旋转了90度
2016/08/15 面试题
乡镇信息公开实施方案
2014/03/23 职场文书
党课知识竞赛主持词
2014/04/01 职场文书
自查自纠工作总结
2014/10/15 职场文书
党员干部作风建设思想汇报范文
2014/10/25 职场文书
门市房租房协议书
2014/12/04 职场文书
就业意向协议书
2015/01/29 职场文书
女性健康知识讲座通知
2015/04/23 职场文书
python中 Flask Web 表单的使用方法
2022/05/20 Python