这几天翻看python语法,看到装饰器这里着实卡了一阵,最初认为也就是个函数指针的用法,但仔细研究后发现,不止这么简单。

首先很多资料将装饰器定义为AOP的范畴,也就是Aspect Oriented Programming面向切面编程的概念,不懂AOP不要紧,只要有函数指针的概念,又有嵌套函数的基础知识,看懂此文一点压力都没有。

先说说为什么要有装饰器这么个东西存在吧,这是一种设计模式,较为经典的有插入日志、性能测试、事务处理等等。概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。

关于嵌套函数,C/C++程序员可能会觉得一头雾水,因为谭老爷子的书明确指出函数不可以嵌套定义,在C++ primer也仅仅有嵌套类的讲解,并不存在嵌套函数一说,但是在一些高级语言中,比如Object C,swift都存在嵌套函数主题,感兴趣的同学可以去翻一下,尤其是当下热门swift,嵌套函数和闭包密不可分,可以方便的实现很多逻辑,比如返回一个函数给调用者。

书归正传,所谓装饰器,顾名思义,就是用来装饰的神器,你有一个函数A(),觉得它不够漂亮,但是又不想重写它,咋办呢?装饰器(Decorator)这时候就派上用场了。

为了方便大家的理解,我先写一个简单的嵌套函数:

def funcA():print("i am funcA()!")def funcB():print("i am funcB()")return funcB
callSth=funcA()//调用funcA得到返回的funcB
callSth()//相当于调用funcB 

值得说明一点,在python里只要你不怕蛋疼,你可以任意嵌套,哪怕你嵌套个百十层直到栈溢出都没问题。

如下:

def ppp():print("return vlaue")
def first():a=10// a被嵌套内的函数捕获!print("the first layer")def second():print("the second layer %d" % a)def third():print("the third layer %d " % a)def forth():print("the forth layer")return ppp()return forthreturn thirdreturn second aaa=first()()()//得到forth()
aaa()

关于嵌套函数是这样执行的,先执行最外层的first(),返回second然后发现后面跟着(),那继续返回third,以此类推,聪明如你,肯定明白了。嵌套函数就这样,简单到爆。如果到这里诸君理解了,装饰器基本上也就理解了。

下面正式开始装饰器的概念(开启摘抄模式):

装饰器的定义很是抽象,我们来看一个小例子。

def foo():print 'in foo()'
foo()

这是一个很无聊的函数没错。但是突然有一个更无聊的人,我们称呼他为B君,说我想看看执行这个函数用了多长时间,好吧,那么我们可以这样做:

import time
def foo():start = time.clock()print 'in foo()'end = time.clock()print 'used:', end - startfoo()

很好,功能看起来无懈可击。可是蛋疼的B君此刻突然不想看这个函数了,他对另一个叫foo2的函数产生了更浓厚的兴趣。

怎么办呢?如果把以上新增加的代码复制到foo2里,这就犯了大忌了~复制什么的难道不是最讨厌了么!而且,如果B君继续看了其他的函数呢?

以不变应万变:还记得吗,函数在Python中是一等公民,那么我们可以考虑重新定义一个函数timeit,将foo的引用传递给他,然后在timeit中调用foo并进行计时,这样,我们就达到了不改动foo定义的目的,而且,不论B君看了多少个函数,我们都不用去修改函数定义了!

import timedef foo():print 'in foo()'def timeit(func):start = time.clock()func()end =time.clock()print 'used:', end - starttimeit(foo)

看起来逻辑上并没有问题,一切都很美好并且运作正常!……等等,我们似乎修改了调用部分的代码。原本我们是这样调用的:foo(),修改以后变成了:timeit(foo)。这样的话,如果foo在N处都被调用了,你就不得不去修改这N处的代码。或者更极端的,考虑其中某处调用的代码无法修改这个情况,比如:这个函数是你交给别人使用的。

最大限度地少改动!

既然如此,我们就来想想办法不修改调用的代码;如果不修改调用代码,也就意味着调用foo()需要产生调用timeit(foo)的效果。我们可以想到将timeit赋值给foo,但是timeit似乎带有一个参数……想办法把参数统一吧!如果timeit(foo)不是直接产生调用效果,而是返回一个与foo参数列表一致的函数的话……就很好办了,将timeit(foo)的返回值赋值给foo,然后,调用foo()的代码完全不用修改!

一个真正意义上的装饰器诞生了:

#-*- coding: UTF-8 -*-
import timedef foo():print 'in foo()'# 定义一个计时器,传入一个,并返回另一个附加了计时功能的方法
def timeit(func):# 定义一个内嵌的包装函数,给传入的函数加上计时功能的包装def wrapper():start = time.clock()func()end =time.clock()print 'used:', end - start# 将包装后的函数返回return wrapperfoo = timeit(foo)
foo()

样,一个简易的计时器就做好了!我们只需要在定义foo以后调用foo之前,加上foo = timeit(foo),就可以达到计时的目的,这也就是装饰器的概念,看起来像是foo被timeit装饰了。在在这个例子中,函数进入和退出时需要计时,这被称为一个横切面(Aspect),这种编程方式被称为面向切面的编程(Aspect-Oriented Programming)。与传统编程习惯的从上往下执行方式相比较而言,像是在函数执行的流程中横向地插入了一段逻辑。在特定的业务领域里,能减少大量重复代码。面向切面编程还有相当多的术语,这里就不多做介绍,感兴趣的话可以去找找相关的资料。

语法糖

上面这段代码看起来似乎已经不能再精简了,Python于是提供了一个语法糖来降低字符输入量。

import timedef timeit(func):def wrapper():start = time.clock()func()end =time.clock()print 'used:', end - startreturn wrapper@timeit// syntax sugar 是也,在定义上加上这一行与另外写foo = timeit(foo)完全等价,千万不要以为@有另外的魔力。除了字符输入少了一些,还有一个额外的好处:这样看上去更有装饰器的感觉。
def foo():print 'in foo()'foo()

给出原文链接:http://www.cnblogs.com/huxi/archive/2011/03/01/1967600.html

相关资料:http://blog.csdn.net/thy38/article/details/4471421

http://www.cnblogs.com/rhcad/archive/2011/12/21/2295507.html

转载于:https://www.cnblogs.com/wangjunyan/p/5046223.html

python之装饰器详解相关推荐

  1. python类装饰器详解-Python类装饰器实现方法详解

    本文实例讲述了Python类装饰器.分享给大家供大家参考,具体如下: 编写类装饰器 类装饰器类似于函数装饰器的概念,但它应用于类,它们可以用于管理类自身,或者用来拦截实例创建调用以管理实例. 单体类 ...

  2. python类装饰器详解-Python 装饰器详解

    开放封闭原则: 开放对扩展 封闭修改源代码 改变了人家调用方式 装饰器结构 """ 默认结构为三层!!!每层返回下一层内存地址就可以进行执行函数, 传参:语法糖中的传参可 ...

  3. python类装饰器详解-Python装饰器详解

    python的装饰器其实是一个语法糖,第一行是@跟着一个表达式:第二行必须以def或者class起始(亦即函数或者class的定义). python的装饰器,必须是可调用的对象,而且必须是可以以一个参 ...

  4. python函数装饰器详解_Python语言函数装饰器用法实例详解

    这篇文章主要介绍了Python语言函数装饰器用法,以实例形式较为详细的分析了Python函数装饰器的常见使用技巧,需要的朋友可以参考下,希望对大家学习Python语言有所帮助. 本文实例讲述了pyth ...

  5. python类装饰器详解-Python类中的装饰器在当前类中的声明与调用详解

    我的Python环境:3.7 在Python类里声明一个装饰器,并在这个类里调用这个装饰器. 代码如下: class Test(): xx = False def __init__(self): pa ...

  6. python类装饰器详解-python 中的装饰器详解

    装饰器 闭包 闭包简单的来说就是一个函数,在该函数内部再定义一个函数,并且这个内部函数用到了外部变量(即是外部函数的参数),最终这个函数返回内部函数的引用,这就是闭包. def decorator(p ...

  7. python类装饰器详解-Python装饰器基础概念与用法详解

    本文实例讲述了Python装饰器基础概念与用法.分享给大家供大家参考,具体如下: 装饰器基础 前面快速介绍了装饰器的语法,在这里,我们将深入装饰器内部工作机制,更详细更系统地介绍装饰器的内容,并学习自 ...

  8. Python @property装饰器详解

    之前的文章中,我们探究了@后接某个自定义函数的用法,实际上,更常见.完备.简单的应用在于对@和python内置的函数进行结合:这可以避免造轮子的行为. 我们知道, Python 内置了3种函数装饰器, ...

  9. python类装饰器详解-Python 类装饰器解析

    1. 类装饰器(都不带参数) class ClassDeco: def __init__(self, func): self.func = func def __call__(self, *args, ...

最新文章

  1. volatile关键字之全面深度剖析
  2. C语言-求字符串长度-strlen()与sizeof()
  3. linux shell编程控制结构:expr、let、for、while、until、shift、if、case、break、continue、函数、select 学习笔记
  4. delphi windows编程_2020年值得关注的新编程V语言Vlang,对标Golang、Rust、Swift
  5. PWN-PRACTICE-BUUCTF-11
  6. 常见浏览器兼容性问题及解决方案
  7. head first python(第三章)–学习笔记
  8. Java 高级算法——数组中查询重复的数字之二
  9. 【转】Java杂谈(四)
  10. python:批量移动指定文件到指定文件夹(模板)
  11. 舒尔特表-遮罩层-计时排序点击 js
  12. Centos搭建socks5代理服务器
  13. 10、Map存储世界杯信息相关操作
  14. html改变按钮形状6,6个HTML5/CSS3按钮悬停边界旋绕动画
  15. python+selenium自动化能打开火狐浏览器但是打不开网址
  16. 针对win10激活出现的一系列问题解决方法
  17. 抽卡游戏的随机机制(转载)
  18. [Code+#4]最短路 (最短路)
  19. 使用 PyTorch 检测眼部疾病
  20. Ray-分布式的SGD

热门文章

  1. Linux C获取文件属性
  2. bash删除文件中的空行
  3. [react] 你最喜欢React的哪一个特性(说一个就好)
  4. React开发(150):判断方法有避免报错
  5. [html] 说说你对HTML5中“一次编写,全体使用”的理解
  6. [html] 说说你对属性data-的理解
  7. 前端学习(2624):state
  8. 前端学习(2225):react之类定义组件
  9. 前端学习(1117):严格模式的变化
  10. 前端学习(872):注册事件兼容性处理