什么是装饰器?

python装饰器(fuctional decorators)就是用于拓展原来函数功能的一种函数,目的是在不改变原函数名(或类名)的情况下,给函数增加新的功能。

这个函数的特殊之处在于它的返回值也是一个函数,这个函数是内嵌“原“”函数的函数。

一般而言,我们要想拓展原来函数代码,最直接的办法就是侵入代码里面修改,例如:

import time
def f():
print("hello")
time.sleep(1)
print("world")  

这是我们最原始的的一个函数,然后我们试图记录下这个函数执行的总时间,那最简单的做法就是改动原来的代码:

import time
def f():
start_time = time.time()
print("hello")
time.sleep(1)
print("world")
end_time = time.time() execution_time = (end_time - start_time)*1000
print("time is %d ms" %execution_time)

但是实际工作中,有些时候核心代码并不可以直接去改,所以在不改动原代码的情况下,我们可以再定义一个函数。(但是生效需要再次执行函数)

import time

def deco(func):
start_time = time.time()
f()
end_time = time.time()
execution_time = (end_time - start_time)*1000
print("time is %d ms" %execution_time) def f():
print("hello")
time.sleep(1)
print("world") if __name__ == '__main__': deco(f)
print("f.__name__ is",f.__name__)
print()

这里我们定义了一个函数deco,它的参数是一个函数,然后给这个函数嵌入了计时功能。但是想要拓展这一千万个函数功能,

就是要执行一千万次deco()函数,所以这样并不理想!接下来,我们可以试着用装饰器来实现,先看看装饰器最原始的面貌。

import time

def deco(f):
def wrapper():
start_time = time.time()
f()
end_time = time.time()
execution_time = (end_time - start_time)*1000
print("time is %d ms" %execution_time )
return wrapper

@deco
def f():
print("hello")
time.sleep(1)
print("world") if __name__ == '__main__':
f()
 

这里的deco函数就是最原始的装饰器,它的参数是一个函数,然后返回值也是一个函数。

其中作为参数的这个函数f()就在返回函数wrapper()的内部执行。然后在函数f()前面加上@deco,

f()函数就相当于被注入了计时功能,现在只要调用f(),它就已经变身为“新的功能更多”的函数了,

(不需要重复执行原函数)。

扩展1:带有固定参数的装饰器

import time

def deco(f):
def wrapper(a,b):
start_time = time.time()
f(a,b)
end_time = time.time()
execution_time = (end_time - start_time)*1000
print("time is %d ms" % execution_time)
return wrapper @deco
def f(a,b):
print("be on")
time.sleep(1)
print("result is %d" %(a+b)) if __name__ == '__main__':
f(3,4)

扩展2:无固定参数的装饰器

import time

def deco(f):
def wrapper(*args, **kwargs):
start_time = time.time()
f(*args, **kwargs)
end_time = time.time()
execution_time_ = (end_time - start_time)*1000
print("time is %d ms" %execution_time)
return wrapper @deco
def f(a,b):
print("be on")
time.sleep(1)
print("result is %d" %(a+b)) @deco
def f2(a,b,c):
print("be on")
time.sleep(1)
print("result is %d" %(a+b+c)) if __name__ == '__main__':
f2(3,4,5)
f(3,4)

扩展3:使用多个装饰器,装饰一个函数

import time

def deco01(f):
def wrapper(*args, **kwargs):
print("this is deco01")
start_time = time.time()
f(*args, **kwargs)
end_time = time.time()
execution_time = (end_time - start_time)*1000
print("time is %d ms" % execution_time)
print("deco01 end here")
return wrapper def deco02(f):
def wrapper(*args, **kwargs):
print("this is deco02")
f(*args, **kwargs) print("deco02 end here")
return wrapper @deco01
@deco02
def f(a,b):
print("be on")
time.sleep(1)
print("result is %d" %(a+b)) if __name__ == '__main__':
f(3,4)


'''
this is deco01
this is deco02
hello,here is a func for add :
result is 7
deco02 end here
time is 1003 ms
deco01 end here
'''

装饰器调用顺序

装饰器是可以叠加使用的,那么使用装饰器以后代码是啥顺序呢?

对于Python中的”@”语法糖,装饰器的调用顺序与使用 @ 语法糖声明的顺序相反。

在这个例子中,”f(3, 4) = deco01(deco02(f(3, 4)))”。

Python内置装饰器

在Python中有三个内置的装饰器,都是跟class相关的:staticmethod、classmethod 和property。

  • staticmethod 是类静态方法,其跟成员方法的区别是没有 self 参数,并且可以在类不进行实例化的情况下调用
  • classmethod 与成员方法的区别在于所接收的第一个参数不是 self (类实例的指针),而是cls(当前类的具体类型)
  • property 是属性的意思,表示可以通过通过类实例直接访问的信息

对于staticmethod和classmethod这里就不介绍了,通过一个例子看看property。

注意,对于Python新式类(new-style class),如果将上面的 “@var.setter” 装饰器所装饰的成员函数去掉,则Foo.var 属性为只读属性,使用 “foo.var = ‘var 2′” 进行赋值时会抛出异常。但是,对于Python classic class,所声明的属性不是 read-only的,所以即使去掉”@var.setter”装饰器也不会报错。

总结

本文介绍了Python装饰器的一些使用,装饰器的代码还是比较容易理解的。只要通过一些例子进行实际操作一下,就很容易理解了。

参考链接:https://blog.csdn.net/xiangxianghehe/article/details/77170585

python装饰器的详细解析的更多相关文章

  1. python 装饰器的详细理解【多次实验】

    demo: # 装饰器其实就是对闭包的使用 print('haha嘻嘻') def hot(): print('知道') def dec(fun): print("call dec" ...

  2. Python 装饰器(Decorators) 超详细分类实例

        Python装饰器分类 Python 装饰器函数: 是指装饰器本身是函数风格的实现; 函数装饰器: 是指被装饰的目标对象是函数;(目标对象); 装饰器类 : 是指装饰器本身是类风格的实现; 类 ...

  3. Python装饰器由浅入深

    装饰器的功能在很多语言中都有,名字也不尽相同,其实它体现的是一种设计模式,强调的是开放封闭原则,更多的用于后期功能升级而不是编写新的代码.装饰器不光能装饰函数,也能装饰其他的对象,比如类,但通常,我们 ...

  4. 自创最精简的python装饰器

    个人心血原创,欢迎转载,请注明作者和出处.否则依法追究法律责任!!!! author:headsen  chen date:2018-03-21  10:37:52 代码: 代码解析过程:1,def ...

  5. python 装饰器 一篇就能讲清楚

    装饰器一直是我们学习python难以理解并且纠结的问题,想要弄明白装饰器,必须理解一下函数式编程概念,并且对python中函数调用语法中的特性有所了解,使用装饰器非常简单,但是写装饰器却很复杂.为了讲 ...

  6. Python高级特性: 12步轻松搞定Python装饰器

    12步轻松搞定Python装饰器 通过 Python 装饰器实现DRY(不重复代码)原则:  http://python.jobbole.com/84151/   基本上一开始很难搞定python的装 ...

  7. python装饰器注意事项

    内容: 1.装饰器基本结构复习 2.装饰器注意事项 python装饰器详细内容:http://www.cnblogs.com/wyb666/p/8748102.html 1.装饰器基本结构复习 装饰器 ...

  8. Python学习:11.Python装饰器讲解(二)

    回顾 上一节我们进行了Python简单装饰器的讲解,但是python的装饰器还有一部分高级的使用方式,这一节就针对python装饰器高级部分进行讲解. 为一个函数添加多个装饰器 今天,老板又交给你一个 ...

  9. python 装饰器 (个人理解就是前置的内建函数)

    感谢有篇文件详细介绍[简单 12 步理解 Python 装饰器]http://python.jobbole.com/85056/ 1.首先介绍内建函数 2.转换为装饰器 3.执行顺序 4.装饰器实用

随机推荐

  1. Visual Studio 2017 配置导出/导入/重置

    1.打开VS,按下面的快捷键呼出命令窗口 Ctrl+Alt+A 2.导入/导出/重置命令 Tools.ImportandExportSettings [/export:filename | /impo ...

  2. Spring中使用Redis

    普通使用Redis的方法很简单,前面的文章也有讲解,这篇文章主要就是讲解通过注解的方式实现Spring和Redis的整合.这里我们创建了3个类:1.Config 全局配置类,相当于xml配置文件2.R ...

  3. Linux下Java环境安装

    本节主要讲解Linux(Centos 6.5)下Java环境的安装 1. 卸载机器上默认安装的JDK 在Linux环境下一般会默认安装jdk,为了自己项目的开发部署,一般情况要重新装jdk,而且自己装 ...

  4. vue分页控件

    下载:https://pan.baidu.com/s/1c125Vgc 一个简单的分页控件: 自动加载模式: 手动加载模式: loading图标使用了iconfont: 主要方法: beginRefr ...

  5. 基于Python——实现解压文件夹中的.zip文件

    [背景]当一个文件夹里存好好多.zip文件需要解压时,手动一个个解压再给文件重命名是一件很麻烦的事情,基于此,今天介绍一种使用python实现批量解压文件夹中的压缩文件并给文件重命名的方法—— [代码 ...

  6. @ControllerAdvice + @ExceptionHandler 全局处理 Controller 层异常

    @ControllerAdvice 和 @ExceptionHandler 的区别 ExceptionHandler, 方法注解, 作用于 Controller 级别. ExceptionHandle ...

  7. 使用ssm(spring+springMVC+mybatis)创建一个简单的查询实例(二)(代码篇)

    这篇是上一篇的延续: 用ssm(spring+springMVC+mybatis)创建一个简单的查询实例(一) 源代码在github上可以下载,地址:https://github.com/guoxia ...

  8. Go程序设计

    01 Go基础特性&独有特性

  9. Typescript中的装饰器原理

    Typescript中的装饰器原理 1.小原理 因为react中的高阶组件本质上是个高阶函数的调用, 所以高阶组件的使用,我们既可以使用函数式方法调用,也可以使用装饰器. 也就是说,装饰器的本质就是一 ...

  10. CF727F [Polycarp's problems] & [EX_Polycarp's problems]

    原题题意 给出长度为n的有序数组,m次询问,每次给出一个正整数x.你要删除数组中最少的元素,使得数组中的前缀和+x都为非负整数.允许离线,n≤750,m≤200,000. 原题思路 首先注意到,x能成 ...