九步学会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内存管理方式和垃圾回收算法解析
Nov 11 Python
Python全排列操作实例分析
Jul 24 Python
TensorFlow打印tensor值的实现方法
Jul 27 Python
Django压缩静态文件的实现方法详析
Aug 26 Python
numpy 对矩阵中Nan的处理:采用平均值的方法
Oct 30 Python
在Pytorch中计算自己模型的FLOPs方式
Dec 30 Python
在tensorflow中实现去除不足一个batch的数据
Jan 20 Python
基于python实现微信好友数据分析(简单)
Feb 16 Python
Python print不能立即打印的解决方式
Feb 19 Python
学会python自动收发邮件 代替你问候女友
May 20 Python
解决pycharm中的run和debug失效无法点击运行
Jun 09 Python
Python requests库参数提交的注意事项总结
Mar 29 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
利用PHP创建动态图像
2006/10/09 PHP
解析用PHP实现var_export的详细介绍
2013/06/20 PHP
php计算整个目录大小的方法
2015/06/19 PHP
thinkphp中的url跳转用法分析
2016/07/12 PHP
ExtJS下 Ext.Direct加载和提交过程排错小结
2013/04/02 Javascript
jquery fancybox ie6不显示关闭按钮的解决办法
2013/12/25 Javascript
JavaScript中的迭代器和生成器详解
2014/10/29 Javascript
JavaScript的原型继承详解
2015/02/15 Javascript
微信企业号开发之微信考勤百度地图定位
2015/09/11 Javascript
jQuery中的一些常见方法小结(推荐)
2016/06/13 Javascript
JavaScript实现页面无操作倒计时退出
2016/10/22 Javascript
纯js实现倒计时功能
2017/01/06 Javascript
JavaScript实现大图轮播效果
2017/01/11 Javascript
nodejs之get/post请求的几种方式小结
2017/07/26 NodeJs
JavaScript数组排序reverse()和sort()方法详解
2017/12/24 Javascript
js 实现复选框只能选择一项的示例代码
2018/01/23 Javascript
vue使用better-scroll实现下拉刷新、上拉加载
2018/11/23 Javascript
[05:24]TI9采访——教练
2019/08/24 DOTA
Python实现连接postgresql数据库的方法分析
2017/12/27 Python
使用Eclipse如何开发python脚本
2018/04/11 Python
Django框架验证码用法实例分析
2019/05/10 Python
python如何基于redis实现ip代理池
2020/01/17 Python
Python tkinter实现日期选择器
2021/02/22 Python
用React加CSS3实现微信拆红包动画效果
2017/03/13 HTML / CSS
同程旅游英文网站:LY.com
2018/11/13 全球购物
教师评优事迹材料
2014/01/10 职场文书
个人求职信范例
2014/01/29 职场文书
学校安全管理责任书
2014/07/23 职场文书
领导班子三严三实心得体会
2014/10/13 职场文书
学校财务管理制度
2015/08/04 职场文书
Python源码解析之List
2021/05/21 Python
浅谈Python3中datetime不同时区转换介绍与踩坑
2021/08/02 Python
Nginx进程调度问题详解
2021/09/25 Servers
Python Flask搭建yolov3目标检测系统详解流程
2021/11/07 Python
警用民用对讲机找不同
2022/02/18 无线电
MySQL派生表联表查询实战过程
2022/03/20 MySQL