python学习——装饰器函数

一、装饰器函数的作用是什么

  答:装饰器函数是在不修改原函数及其调用方式的情况下对原函数功能进行扩展

  对于搞python开发的人来说,函数占据了至关重要的地位。都说学好函数你就可以去找工作了,好了,假如你已经在某个公司上班了,想到马上就要过年了,那过年就意味着你可以向老板要年终奖金了,那凭什么老板要给你年终奖呢,你又能得到多少年终奖金呢。老板是这样说的,你给我至少写1000行代码,我来看一下你代码的执行时间,根据你的执行时间来评你的年终奖。好了,你知道既然要计算时间,学过函数的你就来实现一个计算函数执行时间的函数呗。聪明的你是这样的。

 1 import time
 2
 3 def qqxing():
 4     start = time.time()
 5     print(‘老板好,同事好,大家新年好‘)
 6     end = time.time()
 7     elapsed_time = (end - start)
 8     print(elapsed_time)
 9
10 qqxing()
11
12 #运行结果:老板好,同事好,大家新年好
13 #               0.0

计算函数的执行时间

  实现了计算时间的函数,可是你发现了执行时间为0,因为你写得函数太厉害了,但如果是0的话怕吓到老板,所以你这样搞。

 1 import time
 2
 3 def qqxing():
 4     start = time.time()
 5     time.sleep(0.1)
 6     print(‘老板好,同事好,大家新年好‘)
 7     end = time.time()
 8     elapsed_time = (end - start)
 9     print(elapsed_time)
10
11 qqxing()
12
13 #运行结果:老板好,同事好,大家新年好
14 #          0.10044193267822266

计算函数的执行时间

  ok,虽然实现了,但是你写了500个函数,你难道要每个函数都加上计算时间的函数吗?能不能这样搞?

 1 import time
 2
 3 def timmer(func):
 4     start = time.time()
 5     func()
 6     end = time.time()
 7     print(end - start)
 8
 9 def func1():
10     print(‘func1 over‘)
11
12 def func2():
13     print(‘func2 over‘)
14
15 timmer(func1)
16 timmer(func2)

计算多个函数的执行时间

  这样是不是好多了,基本可以实现,但你会发现实际上当我调用func()函数时,调用方式改变了,由原来的func()变成timmer(func)了,那能不能不改变原函数的调用方式呢?可不可以这样。

 1 import time
 2
 3 def timmer(func):
 4     start = time.time()
 5     func()
 6     end = time.time()
 7     print(end - start)
 8
 9 def func():
10     print(‘func over‘)
11 func = timmer
12 timmer()

不改变函数调用方式

  这样就完美了,可惜我太天真,当执行函数时会报错,因为timmer(func)要传一个值,而你明目张胆的就给python解释器来一个func = timmer,这哪行!而我们在用函数作为变量赋值的时候是没法传参数的。所以你没法了。至此你得出了一个结论:年终奖与我无缘!?????? 但是你是一个不服输的人,冥思苦想了1个小时。得到了如下一个强大的功能。

二、装饰器的形成过程

 1 import time
 2
 3 def timmer(func):
 4     def inner():
 5         start = time.time()
 6         func()
 7         end = time.time()
 8         print(end - start)
 9     return inner
10 def func():
11     time.sleep(0.1)
12     print(‘func over‘)
13 func = timmer(func)
14 func()
15
16 #运行结果: func over
17 #           0.10010719299316406

一个强大的功能

  确实没有改变func()的调用方式。这儿其实你应该知道你用了一个闭包函数,在这儿介绍一下闭包函数。

  什么是闭包函数:即在内部函数中调用外部函数的变量,********注意:外部变量不包含全局变量**********

  但是有个地方很碍眼,就是这个func = timmer(func),你怕老板少给你年终奖,於是你到万能的朋友圈,博客,百度一顿搜索,得到了一颗糖,叫“语法糖” ??

 1 import time
 2
 3 def timmer(func):
 4     def inner():
 5         start = time.time()
 6         func()
 7         end = time.time()
 8         print(end - start)
 9     return inner
10 @timmer
11 def func():
12     time.sleep(0.1)
13     print(‘func over‘)
14 #func = timmer(func)
15 func()

语法糖

  这是一颗很甜的糖,你可开兴了。於是你把语法糖的用法写到了下面??

    语法糖的用法就是,@函数名 其中函数名是装饰器函数的函数名,而且@函数名必须在被装饰的函数上面,虽然他们没有在一起,但他们就像亲人一样。??????

  然后你又小结了一下装饰器??

    装饰器的本质:一个闭包函数

    装饰器的功能:在不修改原函数及其调用方式的情况下对原函数功能进行扩展。

  简单的装饰器如下:

 1 import time
 2
 3 def timmer(func)
 4     def inner()
 5         start = time.time()
 6         func()
 7         print(time.time() - start)
 8     retuan inner
 9
10 @timmer
11 def func()
12     print(‘hello wrapper‘)
13
14 func()    

  其中,定义的timmer(func)是装饰器函数,func()是被装饰的函数,它必须紧紧地挨着语法糖,语法糖就相当于“@timmer ——> func = timmer(func) ”在timmer(func)里面有一个inner(),在inner()里面的func()前面和后面我们可以加一些必要的功能。这才是装饰器真正的厉害之处。

三、装饰器的进阶

  上面我们得到了一个很low的装饰器,但还没完,机智的你会发现你调用函数的时候没有传值,下面我们来说一下传值的问题,学习函数我们知道对形参传值的时候如果你不确定你到底要传多少值的时候我们可以这样传。

1 def func(*args,**kwargs):
2
3     print(‘这是一个万能的传值方式‘)
4
5 func()

  所以我们的装饰器有变了个样??

 1 import time
 2
 3 def timmer(func):
 4     def inner(*args,**kwargs):
 5         start = time.time()
 6         ret = func(*args,**kwargs)
 7         end = time.time()
 8         print(end - start)
 9         return ret
10     return inner
11 @timmer
12 def func1(a,b):
13     time.sleep(0.1)
14     print(‘func1 over and get {} and {}‘.format(a,b))
15 func1(1,[‘a‘,‘b‘,‘c‘])

被装饰的函数带返回值

  此时的装饰器已经堪称完美,但是由于原函数被装饰的原因我们不能查看原函数的“注释”等内容,如下:

 1 import time
 2
 3 def timmer(func):
 4     def inner(*args,**kwargs):
 5         start = time.time()
 6         ret = func(*args,**kwargs)
 7         end = time.time()
 8         print(end - start)
 9         return ret
10     return inner
11 @timmer
12 def func1(a,b):
13     """返回a,b的值"""
14     time.sleep(0.1)
15     print(‘func over and get {} and {}‘.format(a,b))
16     print(func1.__doc__)
17     print(func1.__name__)
18 func1(1,[‘a‘,‘b‘,‘c‘])
19
20 #运行结果: func over and get 1 and [‘a‘, ‘b‘, ‘c‘]
21 #           None
22 #           inner
23 #           0.10055851936340332

不能查看原函数的方法

  所以你有对装饰器函数进行了改装。??

 1 from functools import wraps
 2 import time
 3
 4 def timmer(func):
 5     @wraps(func)
 6     def inner(*args,**kwargs):
 7         start = time.time()
 8         ret = func(*args,**kwargs)
 9         end = time.time()
10         print(end - start)
11         return ret
12     return inner
13 @timmer
14 def func1(a,b):
15     """返回a,b的值"""
16     time.sleep(0.1)
17     print(‘func over and get {} and {}‘.format(a,b))
18     print(func1.__doc__)
19     print(func1.__name__)
20 func1(1,[‘a‘,‘b‘,‘c‘])
21
22 #运行结果:func over and get 1 and [‘a‘, ‘b‘, ‘c‘]
23 #          返回a,b的值
24 #          func1
25 #          0.10077428817749023

改装的装饰器

  这样装饰器基本搞定了。下面再来对装饰器作一些说明。

四、装饰器的再次总结

  1.装饰器是一个在不改变原函数的调用方式的情况下对函数进行拓展;

  2.装饰器的本质是一个闭包函数;

  3.装饰器完美的诠释了编程开发中六大原则之一的“开放封闭原则”

     4.开放封闭原则:

    1.1 对扩展是开放的

    为什么要对扩展开放呢?

    我们说,任何一个程序,不可能在设计之初就已经想好了所有的功能并且未来不做任何更新和修改。所以我们必须允许代码扩展、添加新功能。

    2.1 对修改是封闭的

    为什么要对修改封闭呢?

    就像我们刚刚提到的,因为我们写的一个函数,很有可能已经交付给其他人使用了,如果这个时候我们对其进行了修改,很有可能影响其他已经在使用该函数的用户。

   5. 装饰器的固定模式

 1 from functools import wraps
 2
 3 def timmer(func):
 4     @wraps(func)
 5     def inner(*args,**kwargs):
 6         """在被装饰函数之前添加的功能"""
 7         ret = func(*args,**kwargs)
 8         """在被装饰函数之后添加的功能"""
 9         return ret
10     return inner
11 @timmer
12 def func1(a,b):
13     """返回a,b的值"""
14     print(‘func over and get {} and {}‘.format(a,b))
15
16 func1(1,[‘a‘,‘b‘,‘c‘])

装饰器的固定模式

五、装饰器的拓展
  1.带参数的装饰器

    为了年终奖你费气八力的搞个装饰器蒙混了老板,得到了20个月的年终奖金,那么问题又来了!

    假如你有成千上万个函数使用了一个装饰器,现在你想把这些装饰器都取消掉,你要怎么做?一个一个的取消掉? 没日没夜忙活3天。。。过两天你领导想通了,再让你加上。。。

    崩溃中又带着点庆幸,万一又有奖金呢。继续一顿捣鼓。。。

 1 from functools import wraps
 2
 3 def hahaha(flag):
 4     def timmer(func):
 5         @wraps(func)
 6         def inner(*args,**kwargs):
 7             if flag:
 8                 """在被装饰函数之前添加的功能"""
 9                 print(‘**********‘)
10             ret = func(*args,**kwargs)
11             if flag:
12                 """在被装饰函数之后添加的功能"""
13                 print(‘##########‘)
14             return ret
15         return inner
16     return timmer
17 @hahaha(True)
18 def func1():
19     print(‘哈哈哈‘)
20
21 func1()
22
23 #运行结果:**********
24 #          哈哈哈
25 #          ##########
26
27 from functools import wraps
28
29 def hahaha(flag):
30     def timmer(func):
31         @wraps(func)
32         def inner(*args,**kwargs):
33             if flag:
34                 """在被装饰函数之前添加的功能"""
35                 print(‘**********‘)
36             ret = func(*args,**kwargs)
37             if flag:
38                 """在被装饰函数之后添加的功能"""
39                 print(‘##########‘)
40             return ret
41         return inner
42     return timmer
43 @hahaha(False)
44 def func1():
45     print(‘哈哈哈‘)
46
47 func1()
48
49 # 运行结果:哈哈哈

如何撤销装饰器函数

  不知不觉你又完成了一个强大的功能。只要在语法糖的地方稍稍改一下flag的布尔值就行了。哈哈哈。。。

  *******************注意:装饰器最多只能定义三层嵌套函数,这已经是它的极限了************************

   2. 多个装饰器装饰一个函数  

    在实际的开发项目中,我们还会遇见多个装饰器函数装饰一个函数的情况,请看下面??

 1 from functools import wraps
 2
 3 def wrapper1(func):
 4     def qqxing(*args,**kwargs):
 5         print(‘qqxing‘)
 6         ret1 = func(*args,**kwargs)
 7         print(‘shuangwaiwai‘)
 8         return ret1
 9     return qqxing
10
11 def wrapper2(func):
12     def wahaha(*args,**kwargs):
13         print(‘wahaha‘)
14         ret2 = func(*args,**kwargs)
15         print(‘**************‘)
16         return ret2
17     return wahaha
18 @wrapper2            # func = wrapper2(func)
19 @wrapper1            # func = wrapper1(func)
20 def func():
21     print(‘I am a veryvery handsome boy‘)
22
23 func()
24
25 # 运行结果: wahaha
26 #           qqxing
27 #           I am a veryvery handsome boy
28 #           shuangwaiwai
29 #           **************

多个装饰器装饰一个函数

  如果你仔细看的话,你会发现在装饰器函数中你添加的功能在打印的时候其顺序是关于被装饰的函数的输出内容对称的。是不是和俄罗斯套娃非常相像(虽然我都不知道俄罗斯套娃),如果你把打印的内容改一下就可以更加清楚的观察了,但是我就不改,要改你自己改去。反正写到这儿我感觉好累。不过注意一点,这个程序的执行过程还是有点复杂的,请看下面这张图,我不确定能不能正确的画出来,因为我累╯︿╰

  好了,执行过程大概就这样,所以你要明白,想要别人方便你就得付出更多,但能够作为一个python开发工作人员我乐意,我自豪,我有成就感。    

  这是今天的装饰器函数,若还有什么地方忘记写的以后会补上。

  以上内容参考了Eval_J老师的python之路——装饰器函数,有兴趣的朋友们可以去看一下。She is a very pretty girl。链接 ?? https://www.cnblogs.com/Eva-J/articles/7194277.html#3999110

  

原文地址:https://www.cnblogs.com/lcs-LLH/p/9905439.html

时间: 2024-07-30 05:16:08

python学习——装饰器函数的相关文章

Python学习---装饰器/迭代器/生成器的学习【all】

Python学习---装饰器的学习1210 Python学习---生成器的学习1210 Python学习---迭代器学习1210 原文地址:https://www.cnblogs.com/ftl1012/p/9484145.html

Python学习---装饰器的学习1210

装饰器的基础 学习前提: 作用域 + 函数的理解 + 闭包  [学习,理解] 代码编写原则: 对修改开放对扩展开放 装饰器本质上是一个函数,该函数用来处理其他函数,它可以让其他函数在不需要修改代码的前提下增加额外的功能,装饰器的返回值也是一个函数对象. 装饰器的应用:经常用于有切面需求的场景,比如:插入日志.性能测试.事务处理.缓存.权限校验等应用场景.装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用. 装饰器作用:装饰器感觉就像是内部函数的

python学习-装饰器

参考: http://www.wklken.me/posts/2013/07/19/python-translate-decorator.html http://www.cnblogs.com/wupeiqi/articles/4980620.html 一.装饰器必备知识 1.函数可以被赋值给一个变量 def show(msg): print(msg) # 调用 show 函数 show("这是调用 show() 的输出") # 将函数 show 赋值给 foo foo = show

python学习--装饰器、生成器、内置函数、json

这周学习了装饰器和生成器,写下博客,记录一下装饰器和生成器相关的内容. 一.装饰器 装饰器,这个器就是函数的意思,连起来,就是装饰函数,装饰器本身也是一个函数,它的作用是用来给其他函数添加新功能,比如说,我以前写了很多代码,系统已经上线了,但是性能比较不好,现在想把程序里面每个函数都加一个功能,用来统计每个函数的运行时间是多少,找出来运行比较慢的函数,来优化代码,就需要添加一个新的功能,来统计程序的运行时间,那这样的话,就得修改每个函数了,需要改代码,但是代码特别多,改完了公司倒闭了,这时候装饰

python之装饰器函数

本章内容 引入 装饰器的形成过程 开放封闭原则 谈装饰器主要功能和装饰器固定结构 带参数的装饰器 多个装饰器装饰一个函数 引入 作为一个会写函数的python开发,我们从今天开始要去公司上班了.写了一个函数,就交给其他开发用了. def func1(): print('in func1') 季度末,公司的领导要给大家发绩效奖金了,就提议对这段日子所有人开发的成果进行审核,审核的标准是什么呢?就是统计每个函数的执行时间. 这个时候你要怎么做呀? 你一想,这好办,把函数一改: import time

【Python】装饰器实现日志记录

好的日志对一个软件的重要性是显而易见的.如果函数的入口都要写一行代码来记录日志,这种方式实在是太低效了,但一直没有找到更好的方法.后来用python写一些软件,了解到python的装饰器功能时,突然人品爆发,结合装饰器来记录日志那是绝对的简单有效! 下面简单演示一下用装饰器来协助记录Log,示例代码如下: [python] view plain copy print? #!/usr/bin/env python def trace_func(func): ''''' A decorate fun

python学习笔记之函数总结--高阶函数以及装饰器

python学习笔记之函数总结--高阶函数以及装饰器 Python特点: 1.不是纯函数式编程(允许变量存在): 2.支持高阶函数(可以传入函数作为变量): 3.支持闭包(可以返回函数): 4.有限度的支持匿名函数: 高阶函数: 1.变量可以指向函数: 2.函数的参数可以接收变量: 3.一个函数可以接收另一个函数作为参数: 下面我将示例一些函数的写法以及使用,并说明python中函数的特性: 1.基本的高阶函数示例: #!/usr/bin/env python def func():      

python之装饰器、生成器、内置函数、JSON

一.装饰器: 装饰器,器在这里的意思是函数,也就是装饰函数.作用是给其他函数添加新功能,它可以不改变原有的函数,原来的函数和原来一模一样,什么都不需要改变,只需要在函数外部加上调用哪个装饰器就可以了,装饰器的作用就是不改变原来函数的调用方式,不改变原来函数的代码,给它增加了一个新功能.但是不改变函数,给它增加新功能,那是不可能的,装饰器只不过是偷偷改变了原来的函数而已,而原来的函数不知不觉. 学习装饰器前的知识储备: 1.函数即变量,在python里面函数就是一个变量,函数名就是变量名,函数名里

python之循序渐进学习装饰器

python装饰器的定义:在代码运行期间在不改变原函数定义的基础上,动态给该函数增加功能的方式称之为装饰器(Decorator) 装饰器的优点和用途: 1. 抽离出大量函数中与函数功能本身无关的的雷同代码并继续重用.2. 使用装饰器可以将函数"修饰"为完全不同的行为,可以有效的将业务逻辑正交分解,如用于将权限与身份验证从业务中独立出来.3. 如果一个函数需要一个功能,且这个功能可以被使用在很多函数上,或是函数并不是自己实现,那可以写个装饰器来实现这些功能.概况来说,装饰器的作用就是为已