一文搞懂Python装饰器

曲鸟 2021-10-26 03:21:38
Python 一文 搞懂 装饰

一、前言

本不打算专门写文来讲装饰器的,但有不少粉丝问到了,自己查阅了一些网上的装饰器教程,发现讲的通俗易懂的不多,也有不少照搬的文章。所以我这里专门来讲一讲它。

个人在用的人工智能学习网站推荐给大家:captainai



二、举例说明

假如我们需要对每个函数方法的执行时间做记录,想知道执行一个函数花费了多长时间。

现在先不用装饰器来写,在函数方法体内的开始和结尾各加一个当前时间的输出,然后print打印他们的差值

import time
import datetime
def test():
start_time = datetime.datetime.now()
for i in range(3):
time.sleep(1)
end_time = datetime.datetime.now()
print('执行结束,执行时间为:', end_time - start_time)
test()

输出结果


执行结束,执行时间为: 0:00:03.025049

成功的实现了这个需求,但是出现了一个问题,如果有多个函数方法需要计算执行时间的话,那不就每个函数方法都要加这些代码吗?这样代码量不就大了,还很繁琐冗余吗?


这个时候装饰器就可以大显身手了!

我们可以通过写一个装饰器来实现这个需求,代码如下:

def take_up_time(func):
def run_time():
start_time = datetime.datetime.now()
func()
end_time = datetime.datetime.now()
print('执行结束,执行时间为:', end_time - start_time)
return run_time

加入到需要记录执行时间的方法上

@take_up_time
def test():
for i in range(3):
time.sleep(1)
test()

输出结果

执行结束,执行时间为: 0:00:03.035180

这样就算需要统计多个方法的执行时间,我们只需要在对应函数方法上方加入该装饰器就能实现了,是不是简单多了!

Python语法糖@定义了装饰器,Python装饰器是基于闭包原理对已存在的函数增加额外的功能的设计模式,使得代码简洁且易于维护。


三、装饰器详解

上述例子的装饰器会不会感觉跟其他地方看到的有些许不一样,它们写的装饰器参数都带有*args,**kwargs,类似下面这样的:

def log(func):
def warp(*args, **kwargs):
print("准备开始了")
result = func(*args, **kwargs)
print("马上结束了")
return result
return warp
@log
def add(a, b):
return a + b
print('计算结果为:', add(1, 7))

输出结果


准备开始了
马上结束了
计算结果为: 8

带了这些参数的和之前的举例有什么区别呢?下面为你讲解:

带了*args,**kwargs参数用于获取传递给方法add的参数,上面的add(1,7)中的1和7在装饰器中进行了获取,然后原封不动的将参数传递给被装饰的函数result = func(*args, **kwargs),现在我们把装饰器中将传递的参数打印出来:

def log(func):
def warp(*args, **kwargs):
print('传递的参数为:',args)
result = func(*args, **kwargs)
print("马上结束了")
return result
return warp

装饰器输出结果


传递的参数为 (1, 7)
马上结束了

有没有发现上述*args就把传递的参数(1,7)涵盖了,好像跟**kwargs没什么关系。确实是这样的。对于上面的代码确实与**kwargs无关,甚至我们可以去掉**kwargs这样写:

def log(func):
def warp(*args):
print('传递的参数为:',args)
result = func(*args)
print("马上结束了")
return result
return warp

哪种情况需要**kwargs呢?

当你的参数是默认值参数时,类似下面的代码,c就是一个默认值参数 (如果调用函数的时候未指定c的值则c=0,不然则等于指定的值)

def log(func):
def warp(*args, **kwargs):
print('传递的参数为:',args,kwargs)
result = func(*args, **kwargs)
print("马上结束了")
return result
return warp
@log
def add(a, b,c=0): # 未传递参数C的值时,默认等于0
return a + b+c
print('计算结果为:', add(1, 7,c=1)) # 未传递参数C的值时,默认等于0

输出结果


传递的参数为: (1, 7) {
'c': 1}
马上结束了
计算结果为: 9

通过打印我们发现,c参数的值被放入到kwargs中了。如果我们去掉**kwargs的话,再执行上面的代码就会报错:

def log(func):
def warp(*args):
print('传递的参数为:',args)
result = func(*args)
print("马上结束了")
return result
return warp
@log
def add(a, b,c=0):
return a + b+c
print('计算结果为:', add(1, 7, c=1))

输出结果


在这里插入图片描述


另外我们还可直接对装饰器进行参数的传递:

def log(value):
def decorator(func):
print('传递给装饰器的值为:',value) # 会打印直接传递给装饰器的值
def warp(*args, **kwargs):
print('传递的参数为:', args, kwargs)
result = func(*args, **kwargs)
return result
return warp
return decorator
@log(123) # 传递给装饰器的值
def add(a, b, c=0): # 未传递参数C的值时,默认等于0
return a + b + c
print(add(7, 1))

输出结果

传递给装饰器的值为: 123
传递的参数为: (1, 7) {
}
计算结果为: 8

四、总结

装饰器的应用场景其实很常见,我们常见的判断用户是否登录(token校验的判断)、用户是否有访问权限很多都是使用装饰器来判断的,在DRF(django restframework)中的@api_view@permission_classes就是对请求方法和用户权限的校验:
在这里插入图片描述


完全掌握装饰器相对来说有点难度,需要花一些时间,但这也是必须掌握的python技能。





欢迎关注公众号【曲鸟讲测试开发】,获取最新教程,面试经验、Python知识分享
版权声明
本文为[曲鸟]所创,转载请带上原文链接,感谢
https://blog.csdn.net/momoda118/article/details/120082591

  1. django channels channel_layer.group_send 造成内存溢出
  2. Python布置了个感觉不大理解的题..
  3. Python a posé une question qui ne semblait pas très compréhensible.
  4. Python中yield返回生成器的详细方法
  5. Python函数中apply、map、applymap的区别
  6. Python字符串前加f、r、b、u的不同用法
  7. 5分钟教会你用Python采集CSDN的热榜
  8. 5分鐘教會你用Python采集CSDN的熱榜
  9. 5 minutes pour vous apprendre à utiliser Python pour collecter des listes chaudes de csdn
  10. Quick start of automation -- python (1) - [variables] - half an hour a day
  11. Python爬虫:给我一个链接,快手视频随便下载
  12. Python爬蟲:給我一個鏈接,快手視頻隨便下載
  13. 经验丰富程序员才知道的15种高级Python小技巧
  14. 經驗豐富程序員才知道的15種高級Python小技巧
  15. 15 conseils Python avancés que les programmeurs expérimentés connaissent
  16. Python crawler: Donnez - moi un lien pour télécharger des vidéos rapides
  17. Python爬虫:给我一个链接,快手视频随便下载
  18. [algorithm learning] sword finger offer 64. Find 1 + 2 +... + n (Java / C / C + + / Python / go / trust)
  19. 怎么系统的学习python,有没有一些比较完整的资料,基础知识+框架+项目实战此类pdf
  20. Python crawler: Donnez - moi un lien pour télécharger des vidéos rapides
  21. Python project management and construction, these four tools are enough!
  22. IDE的使用,pycharm引入Python库
  23. In the 120 series columns, you can learn the python beautiful oup4 module, 7000 word blog + climb the ninth workshop network
  24. Django运行xadmin 报错解析 ImportError: cannot import name 'DEFAULT_FORMATS' from 'import_export.admin'
  25. Python程序大学课程写程序
  26. Programme Python Programme d'études collégiales
  27. Python程序大學課程寫程序
  28. Django runxadmin Error resolution importerror: cannot Import name 'default Formats' from 'import _ Export.admin»
  29. Python 函数式编程,看这一篇足够了!
  30. 太棒了!11个好用到起飞的「Python字典」知识点!
  31. 一道Python题目,求解答!
  32. 一道Python題目,求解答!
  33. Un problème Python, s'il vous plaît!
  34. C'est génial! 11 points de connaissance du dictionnaire Python pour le décollage!
  35. Python Functional Programming, This is enough!
  36. 在python中beta分布的问题?
  37. 一个python习题,没有什么头绪,是关于进制的转换和绘制的,想了几天了,不仅仅是2,8,16这种常见的进制转换
  38. Un exercice Python, qui n'a pas beaucoup d'idées, est sur la conversion et le rendu décimaux et a pensé pendant quelques jours, pas seulement 2, 8, 16 cette conversion décimale commune
  39. Un problème avec la distribution bêta en python?
  40. python实现简单的读取excel 内容,报错
  41. L'implémentation Python lit simplement le contenu d'Excel et signale les erreurs
  42. 用Python定义一个函数,接收n个数字,求这些参数数字的和
  43. Définissez une fonction en python, recevez n nombres et additionnez ces nombres de paramètres
  44. 上电Python写文件后,再断电后导致文件内容丢失
  45. 上電Python寫文件後,再斷電後導致文件內容丟失
  46. Une fois que Python est allumé pour écrire des fichiers, le contenu des fichiers est perdu après une panne de courant
  47. python套接字编程报错:ConnectionResetError: [WinError 10054] 远程主机强迫关闭了一个现有的连接。
  48. 【Python从入门到精通】(二)怎么运行Python呢?有哪些好的开发工具(PyCharm)
  49. 【Python从入门到精通】(二)怎么运行Python呢?有哪些好的开发工具(PyCharm)
  50. Python语法1
  51. 2018年度最受推荐的10本Python书籍(初学者必看)
  52. Les 10 livres Python les plus recommandés en 2018 (obligatoire pour les débutants)
  53. Syntaxe Python 1
  54. Python语法1
  55. 在python 运行celery时候 AttributeError: 'NoneType' object has no attribute 'Redis'错误
  56. Attributeerror: 'nonetype' Object has no attribute 'redis' Error when Celery is running in Python
  57. Syntaxe Python 1
  58. Python celery is a plug-in that focuses on distributed asynchronous task processing and task scheduling!
  59. Python celery is a plug-in that focuses on distributed asynchronous task processing and task scheduling!
  60. 在python,使用scrapy爬虫框架