1. 写在前面

在介绍python装饰器之前,首先介绍python的一个概念,对象。在python里,所有的一切皆对象。常用的python对象有整型对象,浮点型对象,字符串对象,列表对象,元组对象,字典对象等。其中一个比较特殊的对象是函数对象。

    num1 = 1         # 定义了一个整型对象,num1引用了这个对象str1 = "aaa"     # 定义了一个字符串对象,str1引用了这个对象list1 = [1,2,3]  # 定义了一个列表对象,list1引用了这个对象def my_func()             # 定义了一个函数对象print "hello world"func1 = my_func           # func1引用了这个函数对象

以一个普通函数为例。

    def my_func(name):return "name is {}".format(name)

这里我们定义了一个名为my_func的函数,传入一个字符串对象作为函数的参数,然后返回另一个字符串对象。在上面已经介绍过了,在python中,一切皆对象。那如果我们把一个函数对象作为参数传入,然后返回另一个函数会怎么样呢?这就是装饰器了。

2. 基础装饰器

接着上面的疑问,我们写一个这样的函数。

    def add(a, b):        # 定义了一个函数对象return a + bmyadd = add           # myadd引用了这个函数对象def decorator1(func):               # 定义了一个函数对象decorator1,所需参数也是一个函数对象def log(*args, **kwargs):       # 在函数内又定义了一个新的函数对象logreturn func(*args, **kwargs)return log                      # 返回这个log函数对象mydecorator = decorator1(myadd)     # 调用函数decorator1,并将myadd作为参数传入,同时将返回的对象赋值给mydecorator, 可知,这里返回的是log函数,# 也就是说,此时mydecorator指向了log函数print mydecorator(1, 2)             # 调用mydecorator函数,即调用内部的log函数

来看一下这段代码的执行结果

    C:\Python>python mydecorator1.py3

我们可以看到它的执行结果就是3,你也许会问写了这么多,不就是两个数的求和吗?不就是上面的add函数吗?上面的代码只是便于让大家理解,如果我们在内部的log函数里加一些操作会怎么样呢?比如打印日志。

    def add(a, b):return a + bmyadd = adddef minus(a, b):return a - bmyminus = minusdef decorator1(func):def log(*args, **kwargs):# do some things here, for example, add some logprint "function {} was called".format(func.__name__)return func(*args, **kwargs)return logmydecorator1 = decorator1(myadd)mydecorator2 = decorator1(myminus)print mydecorator1(1, 2)print mydecorator2(3, 4)

再来看一下这段代码的执行结果

    C:\Python>python mydecorator1.pyfunction add was called3function minus was called-1

我们只需修改内部log函数这一个地方,就可以实现扩充函数的功能,并且这个功能可以应用于多个函数。这就是装饰器最大的意义。这里我是以添加日志为例的,在实际工作中,比如写一个判断是否需要登录操作的装饰器等。

3. python装饰器语法糖

在python的实际工作中,通常使用@符号来调用装饰器,称之为python语法糖。

    def decorator1(func):def log(*args, **kwargs):# do some things here, for example, add some logprint "function {} was called".format(func.__name__)return func(*args, **kwargs)return log@decorator1def add(a, b):      # 此时 add = decorator1(add),add函数就被装饰了return a + b@decorator1def minus(a, b):    # 此时 minus = decorator1(minus),minus函数被装饰了return a - bprint add(1,2)      # 执行装饰好的add函数,而不再是原来的add函数print minus(3,4)    # 执行装饰好的minus函数,而不再是原来的minus函数

4. 装饰器进阶

上面介绍了基础的装饰器,下面再介绍一些装饰器的进阶用法。

4.1 带参数的装饰器

在上面的例子中,我们可以看到被装饰的函数add,minus是带参数的,但是装饰器decorator1本身除了func这个参数外,是不能带有其他参数的。有没有方法能让装饰器带其他参数呢?比如字符串参数等。答案是可以的,只需要在最外层再封装一个函数即可。

    def decorator2(mystring):print mystringdef decorator1(func):def log(*args, **kwargs):# do some things here, for example, add some logprint "function {} was called".format(func.__name__)return func(*args, **kwargs)return logreturn decorator1@decorator2("Used decorator here")def add(a, b):return a + b@decorator2("Used decorator here")def minus(a, b):return a - bprint add(1,2)print minus(3,4)

我们来看这段代码的执行结果

    C:\Python>python mydecorator1.pyUsed decorator hereUsed decorator herefunction add was called3function minus was called-1

4.2 多重装饰

截至目前,我们都只使用了一个装饰器,如果适用多个装饰器效果会怎么样呢?

    from functools import wrapsdef decorator1(func):@wraps(func)def log(*args, **kwargs):# do some things here, for example, add some logprint "function {} was called in decorator1".format(func.__name__)return func(*args, **kwargs)return logdef decorator2(func):@wraps(func)def another_log(*args, **kwargs):# do some things here, for example, add some logprint "function {} was called in decorator2".format(func.__name__)return func(*args, **kwargs)return another_log@decorator1@decorator2def add(a, b):return a + badd(1, 2)@decorator2@decorator1def minus(a, b):return a - bminus(3, 4)

我们来看这段代码的执行结果

    C:\Python>python mydecorator1.pyfunction add was called in decorator1function add was called in decorator2function minus was called in decorator2function minus was called in decorator1

5. 装饰器总结

  1. 装饰器是一个接收函数对象,并且返回一个新的函数对象的函数。

  2. 装饰器可以在不修改被装饰函数的情况下,实现代码功能的扩充,而不需要重写或者重构代码。

  3. 装饰器通常可以用来添加扩充的日志,判断用户某个操作是否需要登录,是否合法等。

  4. 装饰器本身也可以带所需的额外参数。

  5. 对于多重装饰,装饰的顺序为装饰器的调用顺序。

老司机教你 5 分钟读懂 Python 装饰器相关推荐

  1. 利用亚运会,读懂 Python装饰器

    阅读文本大概需要 5 分钟. 2018 年印度雅加达亚运会已接近尾声,中国在金牌榜和总奖牌榜都遥遥领先于第二名的日本,我也是一名体育爱好者,平时有比赛也会看.看到中国的国旗在海外飘扬,内心会格外的自豪 ...

  2. 利用世界杯,读懂 Python 装饰器

    Python 装饰器是在面试过程高频被问到的问题,装饰器也是一个非常好用的特性, 熟练掌握装饰器会让你的编程思路更加宽广,程序也更加 pythonic. 今天就结合最近的世界杯带大家理解下装饰器. 德 ...

  3. 利用世界杯,读懂 Python 装饰器 1

    Python 装饰器是在面试过程高频被问到的问题,装饰器也是一个非常好用的特性, 熟练掌握装饰器会让你的编程思路更加宽广,程序也更加 pythonic. 今天就结合最近的世界杯带大家理解下装饰器. 德 ...

  4. 一文读懂Python 装饰器函数

    [摘要] Python装饰器的学习笔记 1. 初识装饰器 接下来,我们通过一个例子来为大家讲解这个装饰器: 需求介绍:你现在xx科技有限公司的开发部分任职,领导给你一个业务需求让你完成:让你写代码测试 ...

  5. 一文读懂 Python 装饰器

    Python 是一种对新手很友好的语言.但是,它也有很多较难掌握的高级功能,比如装饰器(decorator).很多初学者一直不理解装饰器及其工作原理,在这篇文章中,我们将介绍装饰器的来龙去脉. 在 P ...

  6. 面试系列 | 带你彻底搞懂 Python 装饰器

    本文作者:Rocky0249 公众号:Python空间 写在之前 「装饰器」作为 Python 高级语言特性中的重要部分,是修改函数的一种超级便捷的方式,适当使用能够有效提高代码的可读性和可维护性,非 ...

  7. 一文读懂 @Decorator 装饰器——理解 VS Code 源码的基础

    作者:easonruan,腾讯 CSIG 前端开发工程师 1. 装饰器的样子 我们先来看看 Decorator 装饰器长什么样子,大家可能没在项目中用过 Decorator 装饰器,但多多少少会看过下 ...

  8. python内置模块_三分钟读懂Python内置模块collections

    collections模块 Python内置模块,在内置数据类型(dict.list.set.tuple)的基础上,collections模块还提供了几个额外的数据类型:Counter.deque.d ...

  9. python装饰器函数执行后日志_一篇文章搞懂Python装饰器所有用法

    如果你接触 Python 有一段时间了的话,想必你对 @ 符号一定不陌生了,没错 @ 符号就是装饰器的语法糖. 它放在一个函数开始定义的地方,它就像一顶帽子一样戴在这个函数的头上.和这个函数绑定在一起 ...

最新文章

  1. 超赞的贪吃蛇、吃豆人和数字华容道等童年小游戏1行Python代码就能玩
  2. php中var_dump是什么意思,php中的var_dump()方法的詳細說明
  3. 学好Python能做什么?有哪些从业方向?
  4. 剑指OFFER之二进制中1的个数(九度OJ1513)
  5. mysql 左连接 怎么走索引_mysql left join查询没走索引
  6. 电脑技巧:键盘上ESC按键的使用小技巧,你都知道吗?
  7. 【翻译】.NET 5 Preview2发布
  8. 计算机硬件基础-存取方式
  9. linux关闭交互模式,linux – 关闭cp(copy)命令的交互模式(cp:overwrite?)
  10. eclipse aop连接点joinpoint方法点不出来_(面试必备)你必须要懂的Spring-Aop
  11. cuda Synchronization
  12. 读取文本作为输出字段
  13. 快速 二进制,八进制,十进制,十二进制转换 .源码,反码,补码,
  14. 与复旦大学《数学分析》编者商榷
  15. ToolStrip工具条
  16. python便携版本_python便携版安装tk
  17. 提高文章阅读量的最新技巧
  18. 【示波器的基本使用】以及【示波器按键面板上各个按键含义的介绍】
  19. vijos1027-spfa关键路径-休息中的阿呆
  20. OpenCV 学习第二天

热门文章

  1. SQL-6查找所有员工入职时候的薪水情况,给出emp_no以及salary, 并按照emp_no进行逆序...
  2. 使用System.Timers.Timer类实现程序定时执行
  3. [vijos1162]波浪数
  4. iOS自定义组与组之间的距离以及视图
  5. 【51CTO学院三周年】学业有成啦
  6. Linux学习笔记十三——文件压缩、解压缩和归档
  7. document.getElementsByName和document.getElementById用法
  8. nginx+web.py+fastcgi(spawn-fcgi)的session失效問題
  9. (转载)面试时,你会问面试官哪些问题?
  10. MyBatis启动流程分析