九步学会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中使用scapy模拟数据包实现arp攻击、dns放大攻击例子
Oct 23 Python
Python中__init__.py文件的作用详解
Sep 18 Python
浅谈numpy中linspace的用法 (等差数列创建函数)
Jun 07 Python
Python实现简单的语音识别系统
Dec 13 Python
Python中的heapq模块源码详析
Jan 08 Python
使用Python检测文章抄袭及去重算法原理解析
Jun 14 Python
Python生态圈图像格式转换问题(推荐)
Dec 02 Python
opencv python图像梯度实例详解
Feb 04 Python
python等差数列求和公式前 100 项的和实例
Feb 25 Python
python3实现往mysql中插入datetime类型的数据
Mar 02 Python
Python flask框架实现查询数据库并显示数据
Jun 04 Python
使用Keras建立模型并训练等一系列操作方式
Jul 02 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 函数中使用static的说明
2012/06/01 PHP
Ajax+PHP快速上手及简单应用说明
2013/07/24 PHP
php计划任务之ignore_user_abort函数实现方法
2015/01/08 PHP
PHP中基本HTTP认证技巧分析
2015/03/16 PHP
PHP实现负载均衡下的session共用功能
2018/04/17 PHP
Javascript的匿名函数小结
2009/12/31 Javascript
javascript getElementsByClassName函数
2010/04/01 Javascript
javascript动态控制服务器控件实例
2014/09/05 Javascript
AngularJS的表单使用详解
2015/06/17 Javascript
深入解析AngularJS框架中$scope的作用与生命周期
2016/03/05 Javascript
JS 在数组指定位置插入/删除数据的方法
2017/01/12 Javascript
weui框架实现上传、预览和删除图片功能代码
2017/08/24 Javascript
详解从零搭建 vue2 vue-router2 webpack3 工程
2017/11/22 Javascript
利用vue开发一个所谓的数独方法实例
2017/12/21 Javascript
小程序视频列表中视频的播放与停止的示例代码
2018/07/20 Javascript
浅谈对于react-thunk中间件的简单理解
2019/05/01 Javascript
使用preload预加载页面资源时注意事项
2020/02/03 Javascript
Python中使用copy模块实现列表(list)拷贝
2015/04/14 Python
Python使用bs4获取58同城城市分类的方法
2015/07/08 Python
如何优雅地改进Django中的模板碎片缓存详解
2018/07/04 Python
Python使用到第三方库PyMuPDF图片与pdf相互转换
2019/05/03 Python
python实现广度优先搜索过程解析
2019/10/19 Python
Keras 在fit_generator训练方式中加入图像random_crop操作
2020/07/03 Python
css3 伪元素和伪类选择器详解
2014/09/04 HTML / CSS
小女主人连衣裙:Little Mistress
2017/07/10 全球购物
加拿大折扣、优惠券和交易网站:WagJag
2018/02/07 全球购物
下述程序的作用是计算机数组中的最大元素值及其下标
2012/11/26 面试题
暑期社会实践方案
2014/02/05 职场文书
中层干部竞聘演讲稿
2014/05/15 职场文书
乡镇务虚会发言材料
2014/10/20 职场文书
第二批党的群众路线教育实践活动总结报告
2014/10/30 职场文书
2015医德医风个人工作总结
2015/04/02 职场文书
2019优秀干部竞聘演讲稿范文!
2019/07/02 职场文书
深入理解以DEBUG方式线程的底层运行原理
2021/06/21 Java/Android
vue实现Toast组件轻提示
2022/04/10 Vue.js
vue实力踩坑之push当前页无效
2022/04/10 Vue.js