鱼C论坛

 找回密码
 立即注册
查看: 2356|回复: 0

[技术交流] 从零讲解什么是函数装饰器(修饰符)【重点节选】

[复制链接]
发表于 2021-6-14 15:56:36 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 fc5igm 于 2021-6-14 16:13 编辑

本文节选自《Intermediate Python》的中译本《Python进阶》
原文地址:https://eastlakeside.gitbooks.io/interpy-zh/content/decorators/
转载自:https://www.runoob.com/w3cnote/python-func-decorators.html
本文针对原文中部分对理解装饰器重要关键却未被翻译的文本进行了修改翻译

装饰器(Decorators)是 Python 的一个重要部分。简单地说:他们是修改其他函数的功能的函数。他们有助于让我们的代码更简短,也更Pythonic(Python范儿)。大多数初学者不知道在哪儿使用它们,所以我将要分享下,哪些区域里装饰器可以让你的代码更简洁。 首先,让我们讨论下如何写你自己的装饰器。

这可能是最难掌握的概念之一。我们会每次只讨论一个步骤,这样你能完全理解它。
.
.
.
(原文包含大量基础教学,本转载对此跳过,如需观看,请查看以上两个链接)
.
.
.
将函数作为参数传给另一个函数
  1. def hi():
  2.     return "hi yasoob!"

  3. def doSomethingBeforeHi(func):
  4.     print("我在hi()执行之前")
  5.     print(func())

  6. doSomethingBeforeHi(hi)
  7. #输出:我在hi()执行之前
  8. #     hi yasoob!
复制代码

现在你已经具备所有必需知识,来进一步学习装饰器真正是什么了。装饰器让你在一个函数的前后去执行代码。
你的第一个装饰器
在上一个例子里,其实我们已经创建了一个装饰器!现在我们修改下上一个装饰器,并编写一个稍微更有用点的程序:

  1. def a_new_decorator(a_func): #一个新的装饰器(一个函数)

  2.     def wrapTheFunction(): #对函数进行包裹
  3.         print("我在a_func()执行之前")

  4.         a_func() #一个函数

  5.         print("我在a_func()执行之后")

  6.     return wrapTheFunction

  7. def a_function_requiring_decoration(): #一个需要装饰器的函数
  8.     print("我是那个需要被装饰器修饰的函数")

  9. a_function_requiring_decoration() #一个需要装饰器的函数
  10. #输出: "我是那个需要被装饰器修饰的函数"

  11. a_function_requiring_decoration = a_new_decorator(a_function_requiring_decoration) #一个需要装饰器的函数=一个新的装饰器(一个需要装饰器的函数)
  12. #now a_function_requiring_decoration is wrapped by wrapTheFunction() #现在一个需要装饰器的函数(即a_function_requiring_decoration)被函数warpTheFunction所包裹

  13. a_function_requiring_decoration() #一个需要装饰器的函数
  14. #输出:我在a_func()执行之前
  15. #     我是那个需要被装饰器修饰的函数
  16. #     我在a_func()执行之后
复制代码

你看明白了吗?我们刚刚应用了之前学习到的原理。这正是 python 中装饰器做的事情!它们封装一个函数,并且用这样或者那样的方式来修改它的行为。现在你也许疑惑,我们在代码里并没有使用 @ 符号?那只是一个简短的方式来生成一个被装饰的函数。这里是我们如何使用 @ 来运行之前的代码:

  1. @a_new_decorator
  2. def a_function_requiring_decoration(): #一个需要装饰器的函数
  3.     """请装饰器对我进行修饰!"""
  4.     print("我是那个需要被装饰器 "
  5.           "修饰的函数")

  6. a_function_requiring_decoration() #一个需要装饰器的函数
  7. #输出:我在a_func()执行之前
  8. #     我是那个需要被装饰器修饰的函数
  9. #     我在a_func()执行之后

  10. #the @a_new_decorator is just a short way of saying: #@a_new_decorator只是对如下公式的一种简写表达
  11. a_function_requiring_decoration = a_new_decorator(a_function_requiring_decoration) #一个需要装饰器的函数=一个新的装饰器(一个需要装饰器的函数)
复制代码

希望你现在对 Python 装饰器的工作原理有一个基本的理解。如果我们运行如下代码会存在一个问题:

  1. print(a_function_requiring_decoration.__name__)
  2. # 输出: wrapTheFunction
复制代码

这并不是我们想要的!输出应该是"a_function_requiring_decoration"。这里的函数被warpTheFunction替代了。它重写了我们函数的名字和注释文档(docstring)。幸运的是Python提供给我们一个简单的函数来解决这个问题,那就是functools.wraps。我们修改上一个例子来使用functools.wraps:

  1. from functools import wraps

  2. def a_new_decorator(a_func):
  3.     @wraps(a_func)
  4.     def wrapTheFunction():
  5.         print("我在a_func()执行之前")
  6.         a_func()
  7.         print("我在a_func()执行之后")
  8.     return wrapTheFunction

  9. @a_new_decorator
  10. def a_function_requiring_decoration():
  11.     """请装饰器对我进行修饰!"""
  12.     print("我是那个需要被装饰器"
  13.           "修饰的函数")

  14. print(a_function_requiring_decoration.__name__)
  15. # 输出: a_function_requiring_decoration
复制代码

现在好多了。我们接下来学习装饰器的一些常用场景。

蓝本规范:

  1. from functools import wraps
  2. def decorator_name(f):
  3.     @wraps(f)
  4.     def decorated(*args, **kwargs):
  5.         if not can_run:
  6.             return "Function will not run"
  7.         return f(*args, **kwargs)
  8.     return decorated

  9. @decorator_name
  10. def func():
  11.     return("Function is running")

  12. can_run = True
  13. print(func())
  14. # 输出: Function is running

  15. can_run = False
  16. print(func())
  17. # 输出: Function will not run
复制代码

注意:@wraps接受一个函数来进行装饰,并加入了复制函数名称、注释文档、参数列表等等的功能。这可以让我们在装饰器里面访问在装饰之前的函数的属性。
.
.
.
本段之后的后续标题:
使用场景、带参数的装饰器、装饰器类
具体内容请参阅原文

本帖被以下淘专辑推荐:

小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-6-22 18:24

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表