九步学会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 相关文章推荐
vc6编写python扩展的方法分享
Jan 17 Python
使用Python获取CPU、内存和硬盘等windowns系统信息的2个例子
Apr 15 Python
python中django框架通过正则搜索页面上email地址的方法
Mar 21 Python
python中常用的九种预处理方法分享
Sep 11 Python
python遍历 truple list dictionary的几种方法总结
Sep 11 Python
在pycharm 中添加运行参数的操作方法
Jan 19 Python
如何利用Python分析出微信朋友男女统计图
Jan 25 Python
python简单区块链模拟详解
Jul 03 Python
python如何实现不可变字典inmutabledict
Jan 08 Python
python Timer 类使用介绍
Dec 28 Python
详解python中[-1]、[:-1]、[::-1]、[n::-1]使用方法
Apr 25 Python
浏览器常用基本操作之python3+selenium4自动化测试(基础篇3)
May 21 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开发的一些注意点总结
2010/10/12 PHP
php通过array_push()函数添加多个变量到数组末尾的方法
2015/03/18 PHP
PHP中使用BigMap实例
2015/03/30 PHP
php获取是星期几的的一些常用姿势
2019/12/15 PHP
laravel框架模型和数据库基础操作实例详解
2020/01/25 PHP
javascript 新浪背投广告实现代码
2009/07/07 Javascript
Jquery图形报表插件 jqplot简介及参数详解
2012/10/10 Javascript
前台js改变Session的值(用ajax实现)
2012/12/28 Javascript
javascript实例分享---具有立体效果的图片特效
2014/06/08 Javascript
实现前后端数据交互方法汇总
2015/04/07 Javascript
jQuery-1.9.1源码分析系列(十)事件系统之事件包装
2015/11/20 Javascript
js绘制购物车抛物线动画
2020/11/18 Javascript
Node.js连接postgreSQL并进行数据操作
2016/12/18 Javascript
理解javascript中的闭包
2017/01/11 Javascript
关于ES6的六个小特性(二)
2017/02/20 Javascript
详解node如何让一个端口同时支持https与http
2017/07/04 Javascript
微信小程序用户自定义模版用法实例分析
2017/11/28 Javascript
vue中$refs的用法及作用详解
2018/04/24 Javascript
如何用JavaScript实现功能齐全的单链表详解
2019/02/11 Javascript
微信小程序之几种常见的弹框提示信息实现详解
2019/07/11 Javascript
浅谈Vue 自动化部署打包上线
2020/06/14 Javascript
Element InputNumber计数器的使用方法
2020/07/27 Javascript
javascript实现多边形碰撞检测
2020/10/24 Javascript
Vue使用Ref跨层级获取组件的步骤
2021/01/25 Vue.js
Django1.7+python 2.78+pycharm配置mysql数据库教程
2014/11/18 Python
Python装饰器(decorator)定义与用法详解
2018/02/09 Python
PyQt5每天必学之像素图控件QPixmap
2018/04/19 Python
Python获取网段内ping通IP的方法
2019/01/31 Python
如何用Python来搭建一个简单的推荐系统
2019/08/07 Python
python shell命令行中import多层目录下的模块操作
2020/03/09 Python
python/golang 删除链表中的元素
2020/09/14 Python
英国汽车和货车租赁网站:Hertz英国
2016/09/02 全球购物
建筑安全生产目标责任书
2014/07/23 职场文书
2014年安全员工作总结
2014/11/13 职场文书
质检员岗位职责
2015/02/03 职场文书
幼儿教师辞职信
2015/02/27 职场文书