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实现简单登录验证
Apr 13 Python
Python中is与==判断的区别
Mar 28 Python
对python 读取线的shp文件实例详解
Dec 22 Python
opencv转换颜色空间更改图片背景
Aug 20 Python
python环境下安装opencv库的方法
Mar 05 Python
Python读取配置文件(config.ini)以及写入配置文件
Apr 08 Python
浅析Python 抽象工厂模式的优缺点
Jul 13 Python
Python 实现微信自动回复的方法
Sep 11 Python
python代数式括号有效性检验示例代码
Oct 04 Python
python 实现非极大值抑制算法(Non-maximum suppression, NMS)
Oct 15 Python
pandas数据分组groupby()和统计函数agg()的使用
Mar 04 Python
python百行代码实现汉服圈图片爬取
Nov 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一些服务器端特性的配置加强php的安全
2006/10/09 PHP
利用php来自动调用不同服务器上的flash
2006/10/09 PHP
php 删除无限级目录与文件代码共享
2008/11/22 PHP
php 进度条实现代码
2009/03/10 PHP
phpmyadmin导入(import)文件限制的解决办法
2009/12/11 PHP
php 对输入信息的进行安全过滤的函数代码
2012/06/29 PHP
php使用fsockopen函数发送post,get请求获取网页内容的方法
2014/11/15 PHP
怎样搭建PHP开发环境
2015/07/28 PHP
验证token、回复图文\文本、推送消息的实用微信类php代码
2016/06/28 PHP
laravel + vue实现的数据统计绘图(今天、7天、30天数据)
2018/07/31 PHP
js模拟实现Array的sort方法
2007/12/11 Javascript
jQuery获取URL请求参数的方法
2015/07/18 Javascript
JS+CSS实现简单的二级下拉导航菜单效果
2015/09/21 Javascript
JS简单生成两个数字之间随机数的方法
2016/08/03 Javascript
JS+CSS3模拟溢出滚动效果
2016/08/12 Javascript
JavaScript中的ajax功能的概念和示例详解
2016/10/17 Javascript
浅谈js script标签中的预解析
2016/12/30 Javascript
jQuery插件zTree实现删除树节点的方法示例
2017/03/08 Javascript
几种响应式文字详解
2017/05/19 Javascript
react实现菜单权限控制的方法
2017/12/11 Javascript
vue配置请求本地json数据的方法
2018/04/11 Javascript
关于Angularjs中自定义指令一些有价值的细节和技巧小结
2018/04/22 Javascript
使用jQuery如何写一个含验证码的登录界面
2019/05/13 jQuery
详解element-ui中表单验证的三种方式
2019/09/18 Javascript
[01:00:10]完美世界DOTA2联赛PWL S2 FTD vs Inki 第二场 11.21
2020/11/24 DOTA
Python中的字符串类型基本知识学习教程
2016/02/04 Python
python实现udp聊天窗口
2020/03/31 Python
详解如何解决H5开发使用wx.hideMenuItems无效果不生效
2021/01/20 HTML / CSS
Mistine官方海外旗舰店:泰国国民彩妆品牌
2016/12/28 全球购物
什么是lambda函数
2013/09/17 面试题
2014年酒店前台工作总结
2014/11/14 职场文书
销售员岗位职责
2015/02/10 职场文书
2019年最新证婚词精选集!
2019/06/28 职场文书
golang 在windows中设置环境变量的操作
2021/04/29 Golang
nginx实现动静分离的方法示例
2021/11/07 Servers
Nginx配置根据url参数重定向
2022/04/11 Servers