以前你有没有这样一段经历:很久之前你写过一个函数,现在你突然有了个想法就是你想看看,以前那个函数在你数据集上的运行时间是多少,这时候你可以修改之前代码为它加上计时的功能,但是这样的话是不是还要大体读读你之前的这个的代码,稍微搞清楚一点它的逻辑,才敢给它添加新的东西。这样是不是很繁琐,要是你之前写的代码足够乱足够长,再去读它是不是很抓狂...。实际工作中,我们常常会遇到这样的场景,可能你的需求还不只是这么简单。那么有没有一种可以不对源码做任何修改,并且可以很好的实现你所有需求的手段呢?答案当然是有,这就是今天我们要介绍的python装饰器。有了装饰器,你除了不用担心前面提到的问题,并且还可以很好的处理接下来要做的事:那就是现在你又有了一个新的需求,比如为另一个函数添加计时功能,这时就非常简单了,把要装饰的函数丢给装饰器就好了,它会自动给你添加完功能并返回给你。是不是很神奇?下面我们将一层层剥开它的神秘面纱。

1. 闭包函数

  在看装饰器之前,我们先来搞清楚什么是闭包函数。python是一种面向对象的编程语言,在python中一切皆对象,这样就使得变量所拥有的属性,函数也同样拥有。这样我们就可以理解在函数内创建一个函数的行为是完全合法的。这种函数被叫做内嵌函数,这种函数只可以在外部函数的作用域内被正常调用,在外部函数的作用域之外调用会报错,例如:

       

而如果内部函数里引用了外部函数里定义的对象(甚至是外层之外,但不是全局变量),那么此时内部函数就被称为闭包函数。闭包函数所引用的外部定义的变量被叫做自由变量。闭包从语法上看非常简单,但是却有强大的作用。闭包可以将其自己的代码和作用域以及外部函数的作用结合在一起。下面给出一个简单的闭包的例子:

def count():a = 1b = 1def sum():c = 1return a + c  # a - 自由变量return sum

  

 总结:什么函数可以被称为闭包函数呢?主要是满足两点:函数内部定义的函数;引用了外部变量但非全局变量。

2. python装饰器

  有了闭包函数的概念,我们再去理解装饰器会相对容易一些。python装饰器本质上就是一个函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外的功能,装饰器的返回值也是一个函数对象(函数的指针)。装饰器函数的外部函数传入我要装饰的函数名字,返回经过修饰后函数的名字;内层函数(闭包)负责修饰被修饰函数。从上面这段描述中我们需要记住装饰器的几点属性,以便后面能更好的理解:

    实质: 是一个函数

    参数:是你要装饰的函数名(并非函数调用

    返回:是装饰完的函数名(也非函数调用

    作用:为已经存在的对象添加额外的功能

    特点:不需要对对象做任何的代码上的变动

python装饰器有很多经典的应用场景,比如:插入日志、性能测试、事务处理、权限校验等。装饰器是解决这类问题的绝佳设计。并且从引入中的列子中我们也可以归纳出:装饰器最大的作用就是对于我们已经写好的程序,我们可以抽离出一些雷同的代码组建多个特定功能的装饰器,这样我们就可以针对不同的需求去使用特定的装饰器,这时因为源码去除了大量泛化的内容而使得源码具有更加清晰的逻辑

2.1  函数装饰器

函数的函数装饰器

我们还是以为函数添加计时功能为例,讲述函数装饰器。

import timedef decorator(func):def wrapper(*args, **kwargs):start_time = time.time()func()end_time = time.time()print(end_time - start_time)return wrapper@decorator
def func():time.sleep(0.8)func() # 函数调用
# 输出:0.800644397735595

  

在上面代码中 func是我要装饰器的函数,我想用装饰器显示func函数运行的时间。@decorator这个语法相当于 执行 func = decorator(func),为func函数装饰并返回。在来看一下我们的装饰器函数 - decorator,该函数的传入参数是func (被装饰函数),返回参数是内层函数。这里的内层函数-wrapper,其实就相当于闭包函数,它起到装饰给定函数的作用,wrapper参数为*args, **kwargs。*args表示的参数以列表的形式传入;**kwargs表示的参数以字典的形式传入:

        

从图中我们可以看到:凡是以key=value形式的参数均存在kwargs中,剩下的所有参数都以列表的形式存于args中。这里要注意的是:为了不破坏原函数的逻辑,我们要保证内层函数wrapper和被装饰函数func的传入参数和返回值类型必须保持一致。

类方法的函数装饰器

  类方法的函数装饰器和函数的函数装饰器类似。

import timedef decorator(func):def wrapper(me_instance):start_time = time.time()func(me_instance)end_time = time.time()print(end_time - start_time)return wrapperclass Method(object):@decorator def func(self):time.sleep(0.8)p1 = Method()
p1.func() # 函数调用

  

对于类方法来说,都会有一个默认的参数self,它实际表示的是类的一个实例,所以在装饰器的内部函数wrapper也要传入一个参数 - me_instance就表示将类的实例p1传给wrapper,其他的用法都和函数装饰器相同。

2.2 类装饰器

  前面我们提到的都是让 函数作为装饰器去装饰其他的函数或者方法,那么可不可以让 一个类发挥装饰器的作用呢?答案肯定是可以的,一切皆对象嚒,函数和类本质没有什么不一样。类的装饰器是什么样子的呢?

class Decorator(object):def __init__(self, f):self.f = fdef __call__(self):print("decorator start")self.f()print("decorator end")@Decorator
def func():print("func")func()

  这里有注意的是:__call__()是一个特殊方法,它可将一个类实例变成一个可调用对象:

p = Decorator(func) # p是类Decorator的一个实例
p() # 实现了__call__()方法后,p可以被调用

  

要使用类装饰器必须实现类中的__call__()方法,就相当于将实例变成了一个方法。

2.3  装饰器链

  一个python函数也可以被多个装饰器修饰,要是有多个装饰器时,这些装饰器的执行顺序是怎么样的呢?

        

可见,多个装饰器的执行顺序:是从近到远依次执行。

2.4  python装饰器库 - functools

def decorator(func):def inner_function():passreturn inner_function@decorator
def func():passprint(func.__name__)# 输出: inner_function

 上述代码最后执行的结果不是 func,而是 inner_function!这表示被装饰函数自身的信息丢失了!怎么才能避免这种问题的发生呢?可以借助functools.wraps()函数:
from functools import wraps
def decorator(func):@wraps(func) def inner_function():passreturn inner_function@decorator
def func():passprint(func.__name__)#输出: func

  

转载于:https://www.cnblogs.com/wlzy/p/10547796.html

[转]python 装饰器相关推荐

  1. python简单装饰器_简单介绍Python装饰器(一)

    装饰器的作用 相信大家在 探索过程中已经了解装饰器的作用,也有很多花里胡哨的介绍. 这次小冰也来讲解一下关于Python装饰器的一些小知识. 它的作用: 性能测试 日志 安全验证 ...... 相信大 ...

  2. Python装饰器的神奇功能:自动打印每个方法耗时

    问题: 运行代码时,尤其对于大型项目需要分析每个环节方法耗时的.每个方法前后都写计算耗时及日志打印太繁琐了,而且代码不精简. 解决: Python装饰器类似于Spring的 AOP(Aspect Or ...

  3. python装饰器教学_Python装饰器学习(九步入门)

    这是在Python学习小组上介绍的内容,现学现卖.多练习是好的学习方式. 第一步:最简单的函数,准备附加额外功能 # -*- coding:gbk -*- '''示例1: 最简单的函数,表示调用了两次 ...

  4. 简单介绍python装饰器

    这篇文章简单介绍一下python装饰器,希望对你们有所帮助. 简单正常python例子: def up(text):return text.upper() #转成大写 def lo(text):ret ...

  5. Python装饰器是什么?使用Python装饰器实现计算程序(函数)运行时间的功能

    Python装饰器是什么?使用Python装饰器实现计算程序(函数)运行时间的功能 目录

  6. python 装饰器示例

    python 装饰器示例 import timedef decorator(func): # 传函数def wrapper(*args, **kwargs): # 传参数(也可以传固定参数)start ...

  7. python装饰器与闭包_Python 装饰器和闭包

    Python 装饰器和闭包 装饰器是 Python 中常见的语法糖,这篇文章讲了闭包和装饰器的原理,并且分析了函数中变量的作用域,以及尝试总结了常见的坑. 装饰器基础 首先来看看装饰器的定义:装饰器本 ...

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

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

  9. Python 装饰器记录总结 (终极版)

    Python 装饰器记录总结 (终极版) 原文链接:http://magicroc.com/2017/04/10/Python装饰器记录总结/ 装饰器是一个函数,一个用来包装函数的函数,装饰器在函数申 ...

最新文章

  1. 回文树或者回文自动机,及相关例题
  2. P1712 [NOI2016]区间
  3. 目标检测——模型的快速验证
  4. 前端学习/资源/工具网站
  5. hsqldb mysql_HSQLDB简介
  6. 在html用微信跳转,H5如何跳转微信小程序?
  7. 【智慧城市】智能照明系统解决方案
  8. 阿里云服务器地域的选择
  9. js中输出2000~2100年之间所有的闰年;
  10. macbook linux 双系统,mac安装linux双系统的吐槽
  11. Mysql基础篇(2)—— 单行函数和聚合函数
  12. 大盘为何回血以及盐湖股份和科达制造
  13. 适合程序员的 5 款 Linux 发行版
  14. 程序员忽悠女朋友玩gal
  15. PS学习--图层混合模式详解
  16. 八. IDEA使用和多线程
  17. 第36.5节 动画-跟踪运动中物体的操作器
  18. 音乐人工智能在国内计算机领域虽然有所进步但发展缓慢
  19. 男主计算机系大神甜宠小说,《蜜汁炖鱿鱼》后,又一电竞甜宠小说翻拍,男主帅气颜值直击心脏...
  20. c语言作业制作仓库管理系统,C语言课程设计 仓库管理系统

热门文章

  1. 英特尔将进行重大业务重组
  2. shopnc 支持 支付宝快捷登陆 shopnc权限验证原理说明
  3. 让你知道什么才是firefox4的速度.
  4. 复杂的数据类型5 - C++快速入门11
  5. 从数据库导出数据到word、excel、.txt
  6. 工作报告 2010.12.30
  7. 烂泥:nginx、php-fpm、mysql用户权限解析
  8. 斯坦佛编程教程-Unix编程工具(二)
  9. POJ 3278 Catch That Cow
  10. Request、Request.Form和Request.QueryString的区别