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标准库defaultdict模块使用示例
Apr 28 Python
Python实现读取TXT文件数据并存进内置数据库SQLite3的方法
Aug 08 Python
Python实现的十进制小数与二进制小数相互转换功能
Oct 12 Python
Python实现爬虫抓取与读写、追加到excel文件操作示例
Jun 27 Python
Pycharm之快速定位到某行快捷键的方法
Jan 20 Python
Python实现图片转字符画的代码实例
Feb 22 Python
python实现矩阵打印
Mar 02 Python
TensorBoard 计算图的查看方式
Feb 15 Python
python绘制封闭多边形教程
Feb 18 Python
Python参数传递对象的引用原理解析
May 22 Python
Python爬虫过程解析之多线程获取小米应用商店数据
Nov 14 Python
Python实现钉钉/企业微信自动打卡的示例代码
Feb 02 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数组函数序列之in_array() - 查找数组中是否存在指定值
2011/11/07 PHP
ThinkPHP权限认证Auth实例详解
2014/07/22 PHP
apache和PHP如何整合在一起
2015/10/12 PHP
简要剖析PHP的Yii框架的组件化机制的基本知识
2016/03/17 PHP
利用JQuery+EasyDrag 实现弹出可拖动的Div,同时向Div传值,然后返回Div选中的值
2009/10/24 Javascript
js实现文字跟随鼠标移动而移动的方法
2015/02/28 Javascript
移动端脚本框架Hammer.js
2016/12/15 Javascript
Bootstrap Table使用整理(二)
2017/06/09 Javascript
用js屏蔽被http劫持的浮动广告实现方法
2017/08/10 Javascript
详解Angular5 路由传参的3种方法
2018/04/28 Javascript
Angular5中状态管理的实现
2018/09/03 Javascript
卸载vue2.0并升级vue_cli3.0的实例讲解
2020/02/16 Javascript
vue绑定class的三种方法
2020/12/24 Vue.js
[01:37]全新的一集《真视界》——TI7总决赛
2017/09/21 DOTA
Python Mysql数据库操作 Perl操作Mysql数据库
2009/01/12 Python
Python中除法使用的注意事项
2014/08/21 Python
一步步教你用Python实现2048小游戏
2017/01/19 Python
Python实现统计给定列表中指定数字出现次数的方法
2018/04/11 Python
python 统计列表中不同元素的数量方法
2018/06/29 Python
对pandas将dataframe中某列按照条件赋值的实例讲解
2018/11/29 Python
代码实例讲解python3的编码问题
2019/07/08 Python
python文档字符串(函数使用说明)使用详解
2019/07/30 Python
Python实现打印实心和空心菱形
2019/11/23 Python
Python文本处理简单易懂方法解析
2019/12/19 Python
使用pytorch完成kaggle猫狗图像识别方式
2020/01/10 Python
new_zeros() pytorch版本的转换方式
2020/02/18 Python
部署Django到阿里云服务器教程示例
2020/06/03 Python
css sprite简单实例
2016/05/23 HTML / CSS
美国在线奢侈品寄售商店:Luxury Garage Sale
2018/08/19 全球购物
法律专业实习鉴定
2013/12/22 职场文书
霸王洗发水广告词
2014/03/14 职场文书
高中校园广播稿3篇
2014/09/29 职场文书
全国爱眼日活动总结
2015/02/27 职场文书
办公室主任个人总结
2015/02/28 职场文书
python+pytest接口自动化之token关联登录的实现
2022/04/06 Python
Python创建SQL数据库流程逐步讲解
2022/09/23 Python