鱼C论坛

 找回密码
 立即注册
查看: 100|回复: 2

[已解决]关于装饰器的应用

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

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

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

x
课后作业第46题动手题第0题
import time

def delay(func):
    def funa():
        time.sleep(1)
        func()
    return funa
   
def fib():
    back1, back2 = 0, 1
    @delay
    def func():
        nonlocal back1, back2
        back1, back2 = back2, back1 + back2
        print(back1, end=' ')
    return func
  
def get_fib(n):
    f = fib()
    for i in range(n):
        f()

  
n = int(input("请输入需要获取的斐波那契数:"))

get_fib(n)

这段代码中,为什么不能将修饰器放到函数fib上面??
import time

def delay(func):
    def funa():
        time.sleep(1)
        func()
    return funa
@delay   
def fib():
    back1, back2 = 0, 1
    def func():
        nonlocal back1, back2
        back1, back2 = back2, back1 + back2
        print(back1, end=' ')
    return func
  
def get_fib(n):
    f = fib()
    for i in range(n):
        f()

  
n = int(input("请输入需要获取的斐波那契数:"))

get_fib(n)
最佳答案
2024-5-3 18:49:56
本帖最后由 jackz007 于 2024-5-3 22:25 编辑

        这两句:
  1.     @delay
  2.     def func():
复制代码

        把函数 func() 作为 delay() 的被装饰对象;
  1. def fib():
  2. . . . . . .
  3.     def func():
  4. . . . . .
  5.     return func
复制代码

        fib() 返回的是其内置函数 func() 的调用句柄,那么,下面这一句:
  1.         f = fib()
复制代码

        就会获得对 fib() 内置函数 func() 的调用句柄,下面的语句:
  1.         f()
复制代码

        就是在调用 fib() 的内置函数 func()
        根据装饰器的运行机制,delay() 装饰了 func(),当每次通过 f() 调用 func() 的时候,会把调用转向到 delay(),并由 delay() 来完成对 func() 的实际调用。这样,每次调用 f() 都会经历由 delay() 产生的时间延迟。
        如果改让 delay() 装饰 fib(),那么,在调用 fib() 的时候,会转向到调用 delay(),再由 delay() 来完成对 fib() 的实际调用,所以,只有执行这一句的时候会产生一次时间的延迟:
  1.     f = fib()
复制代码

        而在后面循环中多次调用的 f() 的时候,会直接调用未经 delay() 装饰的 func(),因而期间也不会产生任何延迟。
        此外,用 delay() 装饰 fib() 还有一个问题:
  1. def delay(func):
  2.     def funa():
  3.         time.sleep(1)
  4.         func()                          # <--- 问题语句:函数 funa() 实际完成对被装饰函数的调用,却没有传递函数的返回值。
  5.     return funa
复制代码

        调用 fib() 会返回其内置函数 func() 的调用句柄,如果用 delay() 装饰了 fib(),则会因为 funa() 无返回值,从而使这一句:
  1.     f = fib()
复制代码

        将无法取得 func() 的调用句柄,f 的值将会使 None,从而会使后续的 f() 语句非法。
        如果想让delay() 装饰 fib(),则必须修改 delay()
  1. def delay(func):
  2.     def funa():
  3.         time.sleep(1)
  4.         return func()                          # 修改这里
  5.     return funa
复制代码

        
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2024-5-3 17:45:28 | 显示全部楼层
装饰器的作用是在不改变被修饰函数代码的前提下,为函数添加额外的功能。在第一段代码中,将装饰器放在了内部函数func上面,这样每次调用func时都会执行装饰器的功能,即延迟1秒钟。而将装饰器放在函数fib上面,则说明每次调用fib时都会执行装饰器的功能。但是由于装饰器中使用了内层函数func,而这个函数在装饰器外部并没有定义,所以会报错。

你可以把装饰器放在函数外部,然后再在函数上面使用装饰器。修改后的代码如下:

  1. import time

  2. def delay(func):
  3.     def funa():
  4.         time.sleep(1)
  5.         func()
  6.     return funa
  7.    
  8. @delay
  9. def fib():
  10.     back1, back2 = 0, 1
  11.     def func():
  12.         nonlocal back1, back2
  13.         back1, back2 = back2, back1 + back2
  14.         print(back1, end=' ')
  15.     return func
  16.   
  17. def get_fib(n):
  18.     f = fib()
  19.     for i in range(n):
  20.         f()

  21. n = int(input("请输入需要获取的斐波那契数:"))

  22. get_fib(n)
复制代码


现在,每次调用fib函数时,都会先执行delay装饰器中的代码,延迟1秒钟,然后再执行函数fib中的代码。这样就实现了给fib函数添加延迟执行的功能。

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

使用道具 举报

发表于 2024-5-3 18:49:56 | 显示全部楼层    本楼为最佳答案   
本帖最后由 jackz007 于 2024-5-3 22:25 编辑

        这两句:
  1.     @delay
  2.     def func():
复制代码

        把函数 func() 作为 delay() 的被装饰对象;
  1. def fib():
  2. . . . . . .
  3.     def func():
  4. . . . . .
  5.     return func
复制代码

        fib() 返回的是其内置函数 func() 的调用句柄,那么,下面这一句:
  1.         f = fib()
复制代码

        就会获得对 fib() 内置函数 func() 的调用句柄,下面的语句:
  1.         f()
复制代码

        就是在调用 fib() 的内置函数 func()
        根据装饰器的运行机制,delay() 装饰了 func(),当每次通过 f() 调用 func() 的时候,会把调用转向到 delay(),并由 delay() 来完成对 func() 的实际调用。这样,每次调用 f() 都会经历由 delay() 产生的时间延迟。
        如果改让 delay() 装饰 fib(),那么,在调用 fib() 的时候,会转向到调用 delay(),再由 delay() 来完成对 fib() 的实际调用,所以,只有执行这一句的时候会产生一次时间的延迟:
  1.     f = fib()
复制代码

        而在后面循环中多次调用的 f() 的时候,会直接调用未经 delay() 装饰的 func(),因而期间也不会产生任何延迟。
        此外,用 delay() 装饰 fib() 还有一个问题:
  1. def delay(func):
  2.     def funa():
  3.         time.sleep(1)
  4.         func()                          # <--- 问题语句:函数 funa() 实际完成对被装饰函数的调用,却没有传递函数的返回值。
  5.     return funa
复制代码

        调用 fib() 会返回其内置函数 func() 的调用句柄,如果用 delay() 装饰了 fib(),则会因为 funa() 无返回值,从而使这一句:
  1.     f = fib()
复制代码

        将无法取得 func() 的调用句柄,f 的值将会使 None,从而会使后续的 f() 语句非法。
        如果想让delay() 装饰 fib(),则必须修改 delay()
  1. def delay(func):
  2.     def funa():
  3.         time.sleep(1)
  4.         return func()                          # 修改这里
  5.     return funa
复制代码

        
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-5-18 06:08

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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