什么是装饰器?

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装饰器的更多相关文章

  1. 关于python装饰器

    关于python装饰器,不是系统的介绍,只是说一下某些问题 1 首先了解变量作用于非常重要 2 其次要了解闭包 def logger(func): def inner(*args, **kwargs) ...

  2. python装饰器通俗易懂的解释!

    1.python装饰器 刚刚接触python的装饰器,简直懵逼了,直接不懂什么意思啊有木有,自己都忘了走了多少遍Debug,查了多少遍资料,猜有点点开始明白了.总结了一下解释得比较好的,通俗易懂的来说 ...

  3. Python 装饰器学习

    Python装饰器学习(九步入门)   这是在Python学习小组上介绍的内容,现学现卖.多练习是好的学习方式. 第一步:最简单的函数,准备附加额外功能 1 2 3 4 5 6 7 8 # -*- c ...

  4. python 装饰器修改调整函数参数

    简单记录一下利用python装饰器来调整函数的方法.现在有个需求:参数line范围为1-16,要求把9-16的范围转化为1-8,即9对应1,10对应2,...,16对应8. 下面是例子: def fo ...

  5. python 装饰器学习(decorator)

    最近看到有个装饰器的例子,没看懂, #!/usr/bin/python class decorator(object): def __init__(self,f): print "initi ...

  6. Python装饰器详解

    python中的装饰器是一个用得非常多的东西,我们可以把一些特定的方法.通用的方法写成一个个装饰器,这就为调用这些方法提供一个非常大的便利,如此提高我们代码的可读性以及简洁性,以及可扩展性. 在学习p ...

  7. 关于python装饰器(Decorators)最底层理解的一句话

    一个decorator只是一个带有一个函数作为参数并返回一个替换函数的闭包. http://www.xxx.com/html/2016/pythonhexinbiancheng_0718/1044.h ...

  8. Python装饰器由浅入深

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

  9. Python装饰器与面向切面编程

    今天来讨论一下装饰器.装饰器是一个很著名的设计模式,经常被用于有切面需求的场景,较为经典的有插入日志.性能测试.事务处理等.装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量函数中与函数 ...

  10. python装饰器方法

    前几天向几位新同事介绍项目,被问起了@login_required的实现,我说这是django框架提供的装饰器方法,验证用户是否登录,只要这样用就行了,因为自己不熟,并没有做过多解释. 今天查看dja ...

随机推荐

  1. Go_bufio包

    bufio 是通过缓冲来提高效率. io操作本身的效率并不低,低的是频繁的访问本地磁盘的文件.所以bufio就提供了缓冲区(分配一块内存),读和写都先在缓冲区中,最后再读写文件,来降低访问本地磁盘的次 ...

  2. php 移动操作数组函数

    下面的几个主要是移动数组指针和压入弹出数组元素的和个函数. 函数 功能 array_shift 弹出数组中的第一个元素 array_unshift 在数组的开始处压入元素 array_push 向数组 ...

  3. iframe重新加载

    方法1: document.getElementById('iframeId').contentWindow.location.reload(true); 方法2: document.getEleme ...

  4. mongodb的一些操作

    插入: db.inventory.insert( { _id: 10, type: "misc", item: "card", qty: 15 } ) db.i ...

  5. JavaScript可枚举的属性

    /* 把P中的可枚举属性复制到o中,并返回o中 如果o和p中含有同名的属性,则覆盖O中的属性 这个函数并不处理getter和setter以及复制属性 */ function extend(o,p){ ...

  6. Django框架之ORM的相关操作(二)

    模型类: class Commongity(models.Model): id=models.AutoField(primary_key=True) name=models.CharField(max ...

  7. 最新版的 vscode 怎么配置 Python?

    请进 -- > https://www.zhihu.com/question/322530705/answer/860418884

  8. Sudo临时提权配置

    目录 Sudo临时提权配置 参考 Sudo简介 Sudo配置文件 Sudo配置语法 Sudo配置实例 Sudo日志记录 Sudo临时提权配置

  9. centos 6.5 升级到 python2.7

    准备 centos6.5的python版本默认是2.6.6,可能有的时候我们需要升级到更高的版本,那就来动手升级下吧.我这里以2.7.8版本为例,根据实际需要选择升级版本即可. yum install ...

  10. 校准产品质量,把控出海航向,腾讯WeTest《2019中国移动游戏质量白皮书》正式开放预约

    作者:wetest小编 商业转载请联系腾讯WeTest获得授权,非商业转载请注明出处. 原文链接:https://wetest.qq.com/lab/view/483.html 每当步入一个新的年份, ...