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生成器(Generator)详解
Apr 13 Python
Python基于scrapy采集数据时使用代理服务器的方法
Apr 16 Python
学习python中matplotlib绘图设置坐标轴刻度、文本
Feb 07 Python
PythonWeb项目Django部署在Ubuntu18.04腾讯云主机上
Apr 01 Python
seek引发的python文件读写的问题及解决
Jul 26 Python
Python爬虫库BeautifulSoup的介绍与简单使用实例
Jan 25 Python
python利用递归方法实现求集合的幂集
Sep 07 Python
Python Pillow(PIL)库的用法详解
Sep 19 Python
python安装mysql的依赖包mysql-python操作
Jan 01 Python
Pytorch 中的optimizer使用说明
Mar 03 Python
python文件目录操作之os模块
May 08 Python
教你用python控制安卓手机
May 13 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编程过程中需要了解的this,self,parent的区别
2009/12/30 PHP
php安全开发 添加随机字符串验证,防止伪造跨站请求
2013/02/14 PHP
基于ThinkPHP+uploadify+upload+PHPExcel 无刷新导入数据
2015/09/23 PHP
浅谈PHP eval()函数定义和用法
2016/06/21 PHP
PHP中的访问修饰符简单比较
2019/02/02 PHP
PHP常用函数之格式化时间操作示例
2019/10/21 PHP
Knockout数组(observable)使用详解示例
2013/11/15 Javascript
js简单实现删除记录时的提示效果
2013/12/05 Javascript
js计算时间差代码【包括计算,天,时,分,秒】
2016/04/26 Javascript
JavaScript的ExtJS框架中表格的编写教程
2016/05/21 Javascript
JS实现table表格数据排序功能(可支持动态数据+分页效果)
2016/05/26 Javascript
js 连续赋值的简单实现
2016/06/13 Javascript
ES6概念 Symbol toString()方法
2016/12/25 Javascript
Angular ui-roter 和AngularJS 通过 ocLazyLoad 实现动态(懒)加载模块和依赖
2018/11/25 Javascript
koa2使用ejs和nunjucks作为模板引擎的使用
2018/11/27 Javascript
vue-loader中引入模板预处理器的实现
2019/09/04 Javascript
javascript实现前端成语点击验证优化
2020/06/24 Javascript
使用Vue-scroller页面input框不能触发滑动的问题及解决方法
2020/08/08 Javascript
快速解决vue2+vue-cli3项目ie兼容的问题
2020/11/17 Vue.js
Python根据区号生成手机号码的方法
2015/07/08 Python
在Django同1个页面中的多表单处理详解
2017/01/25 Python
Python 处理数据的实例详解
2017/08/10 Python
浅析NumPy 切片和索引
2020/09/02 Python
美国饼干礼物和美食甜点购买网站:Cheryl’s
2020/05/28 全球购物
介绍Ibatis的核心类
2013/11/18 面试题
营业员实习自我鉴定
2013/12/07 职场文书
周年庆典主持词
2014/04/02 职场文书
出纳试用期自我鉴定
2014/04/07 职场文书
房产委托公证书
2014/04/08 职场文书
阅兵口号
2014/06/19 职场文书
工伤事故赔偿协议书范文
2014/09/24 职场文书
会议接待欢迎词范文
2015/01/26 职场文书
六一活动主持词
2015/06/30 职场文书
上班旷工检讨书
2015/08/15 职场文书
Python中rapidjson参数校验实现
2021/07/25 Python