九步学会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 01 Python
实例说明Python中比较运算符的使用
May 13 Python
Python单体模式的几种常见实现方法详解
Jul 28 Python
Python编程之gui程序实现简单文件浏览器代码
Dec 08 Python
快速了解Python相对导入
Jan 12 Python
Python如何抓取天猫商品详细信息及交易记录
Feb 23 Python
python利用requests库模拟post请求时json的使用教程
Dec 07 Python
python RC4加密操作示例【测试可用】
Sep 26 Python
Python编译成.so文件进行加密后调用的实现
Dec 23 Python
python使用torch随机初始化参数
Mar 22 Python
详解Python内置模块Collections
Mar 22 Python
baselines示例程序train_cartpole.py的ImportError
May 20 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的JSON封装、转变及输出操作示例
2019/09/27 PHP
php反序列化长度变化尾部字符串逃逸(0CTF-2016-piapiapia)
2020/02/15 PHP
Git命令之分支详解
2021/03/02 PHP
Javascript中的delete介绍
2012/09/02 Javascript
基于jQuery创建鼠标悬停效果的方法
2015/03/07 Javascript
纯javascript实现图片延时加载方法
2015/08/21 Javascript
jQuery Uploadify 上传插件出现Http Error 302 错误的解决办法
2015/12/12 Javascript
JQuery fileupload插件实现文件上传功能
2016/03/18 Javascript
微信小程序 框架详解及实例应用
2016/09/26 Javascript
基于JS分页控件实现简单美观仿淘宝分页按钮效果
2016/11/07 Javascript
微信小程序实现打卡日历功能
2020/09/21 Javascript
vue+iview 兼容IE11浏览器的实现方法
2019/01/07 Javascript
微信小程序 select 下拉框组件功能
2019/09/09 Javascript
vue中选中多个选项并且改变选中的样式的实例代码
2020/09/16 Javascript
JavaScript 防抖和节流遇见的奇怪问题及解决
2020/11/20 Javascript
再也不怕 JavaScript 报错了,怎么看怎么处理都在这儿
2020/12/09 Javascript
关于python的bottle框架跨域请求报错问题的处理方法
2017/03/19 Python
OpenCV2.3.1+Python2.7.3+Numpy等的配置解析
2018/01/05 Python
使用Python通过win32 COM打开Excel并添加Sheet的方法
2018/05/02 Python
python3利用tcp实现文件夹远程传输
2018/07/28 Python
python判断自身是否正在运行的方法
2019/08/08 Python
Python学习笔记之While循环用法分析
2019/08/14 Python
Python Opencv提取图片中某种颜色组成的图形的方法
2019/09/19 Python
细数nn.BCELoss与nn.CrossEntropyLoss的区别
2020/02/29 Python
OpenCV Python实现拼图小游戏
2020/03/23 Python
win7上tensorflow2.2.0安装成功 引用DLL load failed时找不到指定模块 tensorflow has no attribute xxx 解决方法
2020/05/20 Python
可视化pytorch 模型中不同BN层的running mean曲线实例
2020/06/24 Python
使用CSS3代码绘制可爱的Hello Kitty猫
2016/08/03 HTML / CSS
美国职棒大联盟官方网上商店:MLBShop.com
2017/11/12 全球购物
高中生活自我鉴定
2014/01/18 职场文书
委托书格式
2014/08/01 职场文书
幼儿园六一活动总结
2014/08/27 职场文书
院党委组织查摆问题对照检查材料思想汇报2014
2014/10/08 职场文书
幼儿园托班开学寄语(2016秋季)
2015/12/03 职场文书
MySQL复制问题的三个参数分析
2021/04/07 MySQL
python获取对象信息的实例详解
2021/07/07 Python