九步学会Python装饰器


Posted in Python onMay 09, 2015

本文实例讲述了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中的身份运算符的使用方法
Oct 13 Python
举例讲解Linux系统下Python调用系统Shell的方法
Nov 07 Python
Python算术运算符实例详解
May 31 Python
Python协程的用法和例子详解
Sep 09 Python
基于python的字节编译详解
Sep 20 Python
浅谈用VSCode写python的正确姿势
Dec 16 Python
Python基于socket实现简单的即时通讯功能示例
Jan 16 Python
解决python 输出是省略号的问题
Apr 19 Python
关于Django ForeignKey 反向查询中filter和_set的效率对比详解
Dec 15 Python
pyqt5 从本地选择图片 并显示在label上的实例
Jun 13 Python
python如何实现不可变字典inmutabledict
Jan 08 Python
安装Anaconda3及使用Jupyter的方法
Oct 27 Python
Python类属性与实例属性用法分析
May 09 #Python
python回调函数用法实例分析
May 09 #Python
python类和函数中使用静态变量的方法
May 09 #Python
Python实用日期时间处理方法汇总
May 09 #Python
python fabric使用笔记
May 09 #Python
Python字符串详细介绍
May 09 #Python
Python urllib、urllib2、httplib抓取网页代码实例
May 09 #Python
You might like
解决MySQL中文输出变成问号的问题
2008/06/05 PHP
php数组对百万数据进行排除重复数据的实现代码
2010/06/08 PHP
php无限极分类递归排序实现方法
2014/11/11 PHP
Laravel Validator自定义错误返回提示消息并在前端展示
2019/05/09 PHP
浅析jquery的作用与优势
2013/12/02 Javascript
jQuery中:input选择器用法实例
2015/01/03 Javascript
常用的JavaScript WEB操作方法分享
2015/02/28 Javascript
js正则匹配出所有图片及图片地址src的方法
2015/06/08 Javascript
AngularJS入门教程之AngularJS 模板
2016/08/18 Javascript
详解vue-cli + webpack 多页面实例应用
2017/04/25 Javascript
基于Vuex无法观察到值变化的解决方法
2018/03/01 Javascript
如何使node也支持从url加载一个module详解
2018/06/05 Javascript
vue实现键盘输入支付密码功能
2018/08/18 Javascript
jquery UI实现autocomplete在获取焦点时得到显示列表功能示例
2019/06/04 jQuery
layui添加动态菜单与选项卡
2019/07/26 Javascript
[39:11]DOTA2上海特级锦标赛C组资格赛#2 LGD VS Newbee第二局
2016/02/28 DOTA
python使用BeautifulSoup分页网页中超链接的方法
2015/04/04 Python
windows及linux环境下永久修改pip镜像源的方法
2016/11/28 Python
Python实现抓取网页生成Excel文件的方法示例
2017/08/05 Python
python使用多线程编写tcp客户端程序
2019/09/02 Python
python单例模式原理与创建方法实例分析
2019/10/26 Python
opencv3/Python 稠密光流calcOpticalFlowFarneback详解
2019/12/11 Python
Python多线程实现支付模拟请求过程解析
2020/04/21 Python
Python使用plt.boxplot() 参数绘制箱线图
2020/06/04 Python
python 对xml解析的示例
2021/02/27 Python
CSS3中的display:grid,网格布局介绍
2019/10/30 HTML / CSS
国际经济贸易专业推荐信
2013/11/06 职场文书
标准化管理实施方案
2014/02/25 职场文书
党员干部承诺书
2014/03/25 职场文书
计算机网络及管理学专业求职信
2014/06/05 职场文书
销售竞赛活动方案
2014/08/23 职场文书
教师求职简历自我评价
2015/03/10 职场文书
音乐之声观后感
2015/06/04 职场文书
四风之害观后感
2015/06/09 职场文书
教你怎么用Python实现多路径迷宫
2021/04/29 Python
面试必问:圣杯布局和双飞翼布局的区别
2021/05/13 HTML / CSS