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创建进程fork用法
Jun 04 Python
Python的Twisted框架上手前所必须了解的异步编程思想
May 25 Python
Pycharm学习教程(1) 定制外观
May 02 Python
django文档学习之applications使用详解
Jan 29 Python
python获取当前目录路径和上级路径的实例
Apr 26 Python
Python OpenCV处理图像之图像像素点操作
Jul 10 Python
python使用PIL给图片添加文字生成海报示例
Aug 17 Python
Python 实现「食行生鲜」签到领积分功能
Sep 26 Python
Python使用字典实现的简单记事本功能示例
Aug 15 Python
python中用logging实现日志滚动和过期日志删除功能
Aug 20 Python
Python接口测试文件上传实例解析
May 22 Python
virtualenv介绍及简明教程
Jun 23 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
一个PHP日历程序
2006/12/06 PHP
如何利用PHP执行.SQL文件
2013/07/05 PHP
PHP引用符&的用法详细解析
2013/08/22 PHP
php使用parse_url和parse_str解析URL
2015/02/22 PHP
使用ThinkPHP的自动完成实现无限级分类实例详解
2016/09/02 PHP
php禁用cookie后session设置方法分析
2016/10/19 PHP
location.search在客户端获取Url参数的方法
2010/06/08 Javascript
js 分页全选或反选标识实现代码
2011/08/09 Javascript
JS跨域总结
2012/08/30 Javascript
Jquery 动态循环输出表格具体方法
2013/11/23 Javascript
nodeJS代码实现计算交社保是否合适
2015/03/09 NodeJs
基于Jquery实现仿百度百科右侧导航代码附源码下载
2015/11/27 Javascript
javascript正则表达式总结
2016/02/29 Javascript
javascript加减乘除的简单实例
2016/07/12 Javascript
Ajax分页插件Pagination从前台jQuery到后端java总结
2016/07/22 Javascript
关于JS中的方法是否加括号的问题
2016/07/27 Javascript
js中常用的Math方法总结
2017/01/12 Javascript
redux中间件之redux-thunk的具体使用
2018/04/17 Javascript
JS实现的透明度渐变动画效果示例
2018/04/28 Javascript
微信小程序自定义组件实现tabs选项卡功能
2018/07/14 Javascript
vue实现固定位置显示功能
2019/05/30 Javascript
JavaScript 常见的继承方式汇总
2020/09/17 Javascript
Python splitlines使用技巧
2008/09/06 Python
Cython 三分钟入门教程
2009/09/17 Python
Python常见数字运算操作实例小结
2019/03/22 Python
Python中使用logging和traceback模块记录日志和跟踪异常
2019/04/09 Python
Python字符串中添加、插入特定字符的方法
2019/09/10 Python
keras CNN卷积核可视化,热度图教程
2020/06/22 Python
Python装饰器如何实现修复过程解析
2020/09/05 Python
怎样在程序里获得一个空指针
2015/01/24 面试题
环境工程与管理大学毕业生求职信
2013/10/02 职场文书
美术指导助理求职信
2014/04/20 职场文书
中国梦演讲稿教师篇
2014/04/23 职场文书
2015年计划生育协会工作总结
2015/05/13 职场文书
Nginx工作原理和优化总结。
2021/04/02 Servers
部分武汉产收音机展览
2022/04/07 无线电