九步学会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 18 Python
Python version 2.7 required, which was not found in the registry
Aug 26 Python
在python中按照特定顺序访问字典的方法详解
Dec 14 Python
python 将对象设置为可迭代的两种实现方法
Jan 21 Python
详解pandas删除缺失数据(pd.dropna()方法)
Jun 25 Python
使用Python为中秋节绘制一块美味的月饼
Sep 11 Python
Python使用Pandas读写Excel实例解析
Nov 19 Python
TENSORFLOW变量作用域(VARIABLE SCOPE)
Jan 10 Python
解决Python中报错TypeError: must be str, not bytes问题
Apr 07 Python
Python3 socket即时通讯脚本实现代码实例(threading多线程)
Jun 01 Python
Python try except else使用详解
Jan 12 Python
Python+Matplotlib图像上指定坐标的位置添加文本标签与注释
Apr 11 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使用ODBC连接数据库的方法
2015/07/18 PHP
JavaScript是否可实现多线程  深入理解JavaScript定时机制
2009/12/22 Javascript
图像替换新技术 状态域方法
2010/01/28 Javascript
关于setInterval、setTimeout在jQuery中的使用注意事项
2011/09/28 Javascript
jquery 关于event.target使用的几点说明介绍
2013/04/26 Javascript
解析prototype,JQuery中跳出each循环的方法
2013/12/12 Javascript
基于javascript实现右下角浮动广告效果
2016/01/08 Javascript
JS模拟的Map类实现方法
2016/06/17 Javascript
3分钟掌握常用的JS操作JSON方法总结
2017/04/25 Javascript
让微信小程序支持ES6中Promise特性的方法详解
2017/06/13 Javascript
easyui datagrid 表格中操作栏 按钮图标不显示的解决方法
2017/07/27 Javascript
微信小程序页面跳转功能之从列表的item项跳转到下一个页面的方法
2017/11/27 Javascript
vue draggable resizable 实现可拖拽缩放的组件功能
2019/07/15 Javascript
Vue使用axios引起的后台session不同操作
2020/08/14 Javascript
vue 解决provide和inject响应的问题
2020/11/12 Javascript
Python最基本的输入输出详解
2015/04/25 Python
举例详解Python中threading模块的几个常用方法
2015/06/18 Python
搭建Python的Django框架环境并建立和运行第一个App的教程
2016/07/02 Python
python3实现UDP协议的服务器和客户端
2017/06/14 Python
python使用openpyxl库修改excel表格数据方法
2018/05/03 Python
python Tkinter版学生管理系统
2019/02/20 Python
详解Python调用系统命令的六种方法
2021/01/28 Python
比利时香水网上商店:NOTINO
2018/03/28 全球购物
与世界上最好的跑步专业品牌合作:Fleet Feet
2019/03/22 全球购物
越南母婴用品购物网站:Kids Plaza
2020/04/09 全球购物
毕业生多媒体设计求职信
2013/10/12 职场文书
银行开业庆典方案
2014/02/06 职场文书
党员党性分析材料
2014/02/17 职场文书
竞选卫生委员演讲稿
2014/04/28 职场文书
会计专业自荐书
2014/07/08 职场文书
机票销售员态度不好检讨书
2014/09/27 职场文书
村主任群众路线教育实践活动个人对照检查材料思想汇报
2014/10/01 职场文书
2016党员读书思廉心得体会
2016/01/23 职场文书
2016年敬老月活动总结
2016/04/05 职场文书
详解JVM系列之内存模型
2021/06/10 Javascript
vue3.0 数字翻牌组件的使用方法详解
2022/04/20 Vue.js