鱼C论坛

 找回密码
 立即注册
查看: 194|回复: 6

装饰器顺序和步骤

[复制链接]
发表于 2024-3-10 13:44:06 | 显示全部楼层 |阅读模式

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

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

x
  1. def add(func):
  2.     def inner():
  3.         x = func()
  4.         return x + 1
  5.     return inner
  6.    
  7. def cube(func):
  8.     def inner():
  9.         x = func()
  10.         return x * x * x
  11.     return inner
  12.    
  13. def square(func):
  14.     def inner():
  15.         x = func()
  16.         return x * x
  17.     return inner
  18.    
  19. @add
  20. @cube
  21. @square
  22. def test():
  23.     return 2
  24.    
  25. print(test())
复制代码



这个结果65能详解一下 装饰器是如何一步一步运行的吗
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2024-3-10 13:44:33 | 显示全部楼层
当我们调用`test()`函数时,装饰器的运行顺序是从下到上的。也就是说,首先运行`square`装饰器,然后是`cube`装饰器,最后是`add`装饰器。

1. 首先,`@square`装饰器将`square`函数作为参数传递给`test`函数,并且将`test`函数的执行结果作为返回值。
2. `square`装饰器内部定义了一个名为`inner`的函数。在`inner`函数内部,它调用了原始的`test`函数,并将其结果赋给变量`x`。然后,它返回了`x * x`。
3. 接下来,`@cube`装饰器将`inner`函数作为参数传递给`test`函数,并且将`test`函数的执行结果作为返回值。
4. `cube`装饰器内部定义了一个名为`inner`的函数。在`inner`函数内部,它调用了`inner`函数(由`@square`装饰器创建),并将其结果赋给变量`x`。然后,它返回了`x * x * x`。
5. 最后,`@add`装饰器将`inner`函数作为参数传递给`test`函数,并且将`test`函数的执行结果作为返回值。
6. `add`装饰器内部定义了一个名为`inner`的函数。在`inner`函数内部,它调用了`inner`函数(由`@cube`装饰器创建),并将其结果赋给变量`x`。然后,它返回了`x + 1`。
7. 最终,当我们调用`test()`函数时,实际上是调用了`add`装饰器返回的`inner`函数。`inner`函数又调用了`cube`装饰器返回的`inner`函数,最后调用了`square`装饰器返回的`inner`函数。完成所有的运算后,返回结果65。

所以,整个过程可以理解为:

1. `square`装饰器计算结果:2 * 2 = 4。
2. `cube`装饰器计算结果:4 * 4 * 4 = 64。
3. `add`装饰器计算结果:64 + 1 = 65。

希望这个解释能够帮助你理解装饰器的执行顺序和步骤。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-3-10 16:47:33 | 显示全部楼层
本帖最后由 jackz007 于 2024-3-10 19:45 编辑

        也许去掉装饰器,更加能够帮助楼主理解装饰器的作用
        下面的代码人工实现装饰器的功能和效果
  1. def add(func):
  2.     def inner():
  3.         x = func()
  4.         return x + 1
  5.     return inner
  6.    
  7. def cube(func):
  8.     def inner():
  9.         x = func()
  10.         return x * x * x
  11.     return inner
  12.    
  13. def square(func):
  14.     def inner():
  15.         x = func()
  16.         return x * x
  17.     return inner
  18.    
  19. #@add                               # 注意这里
  20. #@cube                              # 注意这里
  21. #@square                            # 注意这里
  22. def test():
  23.     return 2
  24.    
  25. #print(test())                      # 注意这里
  26. print(add(cube(square(test)))())    # 注意这里
复制代码
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-3-10 21:08:33 | 显示全部楼层
FishC 发表于 2024-3-10 13:44
当我们调用`test()`函数时,装饰器的运行顺序是从下到上的。也就是说,首先运行`square`装饰器,然后是`cub ...

叠加装饰器有没有具体教程,举例讲解一下吧
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-3-10 21:08:56 | 显示全部楼层
lc88824 发表于 2024-03-10 21:08
叠加装饰器有没有具体教程,举例讲解一下吧


当然!下面我将通过一个具体的例子来讲解叠加装饰器的使用。

假设我们有一个函数`say_hello()`,我们想要给它添加两个装饰器,一个是用于在函数执行前打印一条消息,另一个是用于在函数执行后打印一条消息。

首先,我们定义这两个装饰器:

  1. def before(func):
  2.     def wrapper():
  3.         print("在函数执行前打印一条消息")
  4.         func()
  5.     return wrapper

  6. def after(func):
  7.     def wrapper():
  8.         func()
  9.         print("在函数执行后打印一条消息")
  10.     return wrapper
复制代码


然后,我们应用这两个装饰器到`say_hello()`函数:

  1. @after
  2. @before
  3. def say_hello():
  4.     print("Hello, World!")
复制代码


现在,当我们调用`say_hello()`函数时,会按照以下顺序运行装饰器:

1. `@before`装饰器会将`say_hello`函数作为参数传递给`before`装饰器,并将`before`装饰器返回的`wrapper`函数作为`say_hello`函数的新定义。这样,原来的`say_hello`函数就被替换成了`wrapper`函数。

2. `@after`装饰器会将上一步得到的`wrapper`函数作为参数传递给`after`装饰器,并将`after`装饰器返回的`wrapper`函数作为最终的`say_hello`函数的新定义。这样,又一次替换了`say_hello`函数的定义。

最终,当我们调用`say_hello()`函数时,会依次执行以下操作:

1. `@before`装饰器中的`wrapper`函数会在函数执行前打印一条消息。

2. `@after`装饰器中的`wrapper`函数会在函数执行后打印一条消息。

3. `say_hello`函数本身通过`print("Hello, World!")`语句打印出"Hello, World!"。

完整的代码如下所示:

  1. def before(func):
  2.     def wrapper():
  3.         print("在函数执行前打印一条消息")
  4.         func()
  5.     return wrapper

  6. def after(func):
  7.     def wrapper():
  8.         func()
  9.         print("在函数执行后打印一条消息")
  10.     return wrapper

  11. @after
  12. @before
  13. def say_hello():
  14.     print("Hello, World!")

  15. say_hello()  # 调用函数
复制代码


运行以上代码,输出结果为:

  1. 在函数执行前打印一条消息
  2. Hello, World!
  3. 在函数执行后打印一条消息
复制代码


希望这个例子能够帮助你理解叠加装饰器的用法!

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-3-11 11:45:21 From FishC Mobile | 显示全部楼层
FishC 发表于 2024-3-10 21:08
当然!下面我将通过一个具体的例子来讲解叠加装饰器的使用。

假设我们有一个函数`say_hello()`,我 ...

为什么在函数内外层print打印是按照由下而上输出,里面函数调用就是由上而下的。本例中是哪种情况,这俩情况怎么区分
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-3-11 11:45:39 | 显示全部楼层
lc88824 发表于 2024-03-11 11:45
为什么在函数内外层print打印是按照由下而上输出,里 ...


这里会有一个区分的误解。

在 Python 中,函数的执行顺序是按照代码的顺序从上到下依次执行的,也就是说,在函数内部,代码是按照由上而下的顺序执行的。所以,无论是在装饰器内部还是在函数内部,都是由上而下依次执行的。

在你提到的例子中:

  1. def before(func):
  2.     def wrapper():
  3.         print("在函数执行前打印一条消息")
  4.         func()
  5.     return wrapper

  6. def after(func):
  7.     def wrapper():
  8.         func()
  9.         print("在函数执行后打印一条消息")
  10.     return wrapper

  11. @after
  12. @before
  13. def say_hello():
  14.     print("Hello, World!")

  15. say_hello()
复制代码


先应用的是 `@before` 装饰器,然后才是 `@after` 装饰器。所以,最终的执行顺序是:

1.  `@before` 装饰器中的 `wrapper` 函数首先执行,在函数执行前打印一条消息。
2. `@after` 装饰器中的 `wrapper` 函数执行 `func()`,即调用被装饰的函数 `say_hello()`。
3. `say_hello` 函数本身通过 `print("Hello, World!")` 语句打印出 "Hello, World!"。
4. `@after` 装饰器中的 `wrapper` 函数在函数执行后打印一条消息。

这就是为什么你看到的打印顺序是 `@before` 打印在前,`say_hello()` 打印在中间,`@after` 打印在后面。

希望这解释清楚了你的疑惑,如果还有其他问题,请随时提问。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-4-29 00:30

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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