鱼C论坛

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

装饰器顺序和步骤

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

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

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

x
def add(func):
    def inner():
        x = func()
        return x + 1
    return inner
    
def cube(func):
    def inner():
        x = func()
        return x * x * x
    return inner
    
def square(func):
    def inner():
        x = func()
        return x * x
    return inner
    
@add
@cube
@square
def test():
    return 2
    
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 编辑

        也许去掉装饰器,更加能够帮助楼主理解装饰器的作用
        下面的代码人工实现装饰器的功能和效果
def add(func):
    def inner():
        x = func()
        return x + 1
    return inner
    
def cube(func):
    def inner():
        x = func()
        return x * x * x
    return inner
    
def square(func):
    def inner():
        x = func()
        return x * x
    return inner
    
#@add                               # 注意这里
#@cube                              # 注意这里
#@square                            # 注意这里
def test():
    return 2
    
#print(test())                      # 注意这里
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()`,我们想要给它添加两个装饰器,一个是用于在函数执行前打印一条消息,另一个是用于在函数执行后打印一条消息。

首先,我们定义这两个装饰器:
def before(func):
    def wrapper():
        print("在函数执行前打印一条消息")
        func()
    return wrapper

def after(func):
    def wrapper():
        func()
        print("在函数执行后打印一条消息")
    return wrapper

然后,我们应用这两个装饰器到`say_hello()`函数:
@after
@before
def say_hello():
    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!"。

完整的代码如下所示:
def before(func):
    def wrapper():
        print("在函数执行前打印一条消息")
        func()
    return wrapper

def after(func):
    def wrapper():
        func()
        print("在函数执行后打印一条消息")
    return wrapper

@after
@before
def say_hello():
    print("Hello, World!")

say_hello()  # 调用函数

运行以上代码,输出结果为:
在函数执行前打印一条消息
Hello, World!
在函数执行后打印一条消息

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

以上回复来自 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 中,函数的执行顺序是按照代码的顺序从上到下依次执行的,也就是说,在函数内部,代码是按照由上而下的顺序执行的。所以,无论是在装饰器内部还是在函数内部,都是由上而下依次执行的。

在你提到的例子中:
def before(func):
    def wrapper():
        print("在函数执行前打印一条消息")
        func()
    return wrapper

def after(func):
    def wrapper():
        func()
        print("在函数执行后打印一条消息")
    return wrapper

@after
@before
def say_hello():
    print("Hello, World!")

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-9-22 08:28

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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