我们先看一个闭包的例子:

  1. from time import ctime
  2.  
  3. def before_call(f):
  4. def wrapped(*args, **kargs):
  5. print 'before calling, now is %s' % ctime()
  6. return f(*args, **kargs)
  7. return wrapped
  8.  
  9. def test(name):
  10. print 'hello, %s' % (name)
  11.  
  12. if __name__ == '__main__':
  13. before_call(test)("lucky")

我们先看运行结果:

  1. ~/Documents/py python 2.py
  2. before calling, now is Sat Dec 27 21:30:18 2014
  3. hello, lucky

上面的代码使用了闭包,因为子函数wrapped将父函数的内部变量f与之绑定。

这样,wrapped这个闭包函数,实际上先打印时间,然后调用f,所以正如结果打印的一般,before_call起到的是一种装饰的作用。

 

这里我扩展它的功能,增加一个调用函数后,打印时间:

  1. from time import ctime
  2.  
  3. def before_call(f):
  4. def wrapped(*args, **kargs):
  5. print 'before calling, now is %s' % ctime()
  6. return f(*args, **kargs)
  7. return wrapped
  8.  
  9. def after_call(f):
  10. def wrapped(*args, **kargs):
  11. try:
  12. return f(*args, **kargs)
  13. finally:
  14. print 'after calling, now is %s' % ctime()
  15. return wrapped
  16.  
  17. def test(name):
  18. print 'hello, %s' % (name)
  19.  
  20. if __name__ == '__main__':
  21. before_call(test)("lucky")
  22. after_call(test)("peter")
  23. before_call(after_call(test))("john")
  24. after_call(before_call(test))('marry')

运行结果为:

  1. ~/Documents/py python 2.py
  2. before calling, now is Sat Dec 27 21:37:24 2014
  3. hello, lucky
  4. hello, peter
  5. after calling, now is Sat Dec 27 21:37:24 2014
  6. before calling, now is Sat Dec 27 21:37:24 2014
  7. hello, john
  8. after calling, now is Sat Dec 27 21:37:24 2014
  9. before calling, now is Sat Dec 27 21:37:24 2014
  10. hello, marry
  11. after calling, now is Sat Dec 27 21:37:24 2014

运行结果是正确的。注意最后两个,顺序交换了,对结果无影响。

 

下面我们再包装一层:

  1. def after_call():
  2. def after(f):
  3. def wrapped(*args, **kargs):
  4. try:
  5. return f(*args, **kargs)
  6. finally:
  7. print 'after calling, now is %s' % ctime()
  8. return wrapped
  9. return after
  10.  
  11. def before_call():
  12. def before(f):
  13. def wrapped(*args, **kargs):
  14. print 'before calling, now is %s' % ctime()
  15. return f(*args, **kargs)
  16. return wrapped
  17. return before

那么如何使用呢?这里就是python装饰器的语法,

如果我们这样使用:

  1. @before_call()
  2. def test(name):
  3. print 'hello, %s' % (name)
  4.  
  5. if __name__ == '__main__':
  6. test("lucky")

注意test函数前加了装饰的符号。

还可以这样:

  1. @after_call()
  2. def test(name):
  3. print 'hello, %s' % (name)

甚至可以嵌套多层:

  1. @before_call()
  2. @after_call()
  3. def test(name):
  4. print 'hello, %s' % (name)

 

这就是python中装饰器的原理,内部采用了闭包。

Python闭包的高级应用-装饰器的实现的更多相关文章

  1. python高级之装饰器

    python高级之装饰器 本节内容 高阶函数 嵌套函数及闭包 装饰器 装饰器带参数 装饰器的嵌套 functools.wraps模块 递归函数被装饰 1.高阶函数 高阶函数的定义: 满足下面两个条件之 ...

  2. 第二篇:python高级之装饰器

    python高级之装饰器   python高级之装饰器 本节内容 高阶函数 嵌套函数及闭包 装饰器 装饰器带参数 装饰器的嵌套 functools.wraps模块 递归函数被装饰 1.高阶函数 高阶函 ...

  3. python中函数总结之装饰器闭包

    1.前言 函数也是一个对象,从而可以增加属性,使用句点来表示属性. 如果内部函数的定义包含了在外部函数中定义的对象的引用(外部对象可以是在外部函数之外),那么内部函数被称之为闭包. 2.装饰器 装饰器 ...

  4. 简学Python第四章__装饰器、迭代器、列表生成式

    Python第四章__装饰器.迭代器 欢迎加入Linux_Python学习群  群号:478616847 目录: 列表生成式 生成器 迭代器 单层装饰器(无参) 多层装饰器(有参) 冒泡算法 代码开发 ...

  5. Python全栈开发之---装饰器

    1.装饰器的形成过程 import time def func1(): print('in func1') def timer(func): def inner(): start = time.tim ...

  6. 初学 Python(十五)——装饰器

    初学 Python(十五)--装饰器 初学 Python,主要整理一些学习到的知识点,这次是生成器. #-*- coding:utf-8 -*- import functools def curren ...

  7. 十一. Python基础(11)—补充: 作用域 & 装饰器

    十一. Python基础(11)-补充: 作用域 & 装饰器 1 ● Python的作用域补遗 在C/C++等语言中, if语句等控制结构(control structure)会产生新的作用域 ...

  8. Python 函数修饰符(装饰器)的使用

     Python 函数修饰符(装饰器)的使用 1.  修饰符的来源修饰符是一个很著名的设计模式,经常被用于有切面需求的场景,较为经典的有插入日志.性能测试.事务处理等. 修饰符是解决这类问题的绝佳设计, ...

  9. Python 标准库中的装饰器

    题目描述 1.简单举例 Python 标准库中的装饰器 2.说说你用过的 Python 标准库中的装饰器 1. 首先,我们比较熟悉,也是比较常用的 Python 标准库提供的装饰器有:property ...

随机推荐

  1. DRF最高封装的子类视图

    # 转载请留言联系 子类视图: 视图 作用 方法 父类 ListAPIView 查询多条数据 get GenericAPIView ListModelMixin CreateAPIView 新增一条数 ...

  2. 剑指offer 面试题5 : 从尾到头打印链表

    题目: 输入一个链表的头结点,从尾到头反过来打印出每个节点的值.链表结点定义如下: struct ListNode { int m_nKey; ListNode* m_pNext; }; 思路: 通常 ...

  3. 子类构造函数 supper关键字

    在导出类的构造函数,如果没有明确指定调用哪一个基类构造器,它会默默调用默认构造器. 如果不存在默认构造器,编译器就会报错. java编程思想 p158(p194)

  4. KVM(七)使用 libvirt 做 QEMU/KVM 快照和 Nova 实例的快照

    本文将梳理 QEMU/KVM 快照相关的知识,以及在 OpenStack Nova 中使用 libvirt 来对 QEMU/KVM 虚机做快照的过程. 1. QEMU/KVM 快照 1.1 概念 QE ...

  5. KVM(三)I/O 全虚拟化和准虚拟化

    在 QEMU/KVM 中,客户机可以使用的设备大致可分为三类: 1. 模拟设备:完全由 QEMU 纯软件模拟的设备. 2. Virtio 设备:实现 VIRTIO API 的半虚拟化设备. 3. PC ...

  6. k8s的持久化存储PV&&PVC

    1.PV和PVC的引入 Volume 提供了非常好的数据持久化方案,不过在可管理性上还有不足. 拿前面 AWS EBS 的例子来说,要使用 Volume,Pod 必须事先知道如下信息: 当前 Volu ...

  7. 前段基础JavaScript

    JavaScript概述 JavaScript的历史 1992年Nombas开发出C-minus-minus(C--)的嵌入式脚本语言(最初绑定在CEnvi软件中).后将其改名ScriptEase.( ...

  8. hdu 1669(二分图多重匹配)

    Jamie's Contact Groups Time Limit: 15000/7000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/ ...

  9. Linux 下 UltraEdit 版本 破解 30 天试用限制

    原创 http://yhz61010.iteye.com/blog/2319599 rm -rfd ~/.idm/uex rm -rf ~/.idm/*.spl rm -rf /tmp/*.spl 一 ...

  10. 20、Django实战第20天:课程详情页

    1.把course-detail.html复制到templates目录下 2.编辑course-detail.html,分析页面,继承base.html 3.编辑courses.views .... ...