鱼C论坛

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

函数装饰器的困惑

[复制链接]
发表于 2025-2-8 20:58:48 | 显示全部楼层 |阅读模式

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

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

x
我在学习小甲鱼老师函数装饰器的课程,写了以下代码:
def time_master(func):
    def call_func():
       print('开始记录时间')
       start = time.time()
       func()
       end = time.time()
       print('时间记录终止')
       print(f'一共耗时:{(end - start)}')
    return call_func

@time_master
def myfunc():
time.sleep(5)

myfunc()
>>>开始记录时间
时间记录终止
一共耗时:5.001526355743408

但如果我在定义time_master(func)函数时,里面没有定义call_func()函数,而是只有一层函数体,此时在定义后面的myfunc()函数并加上@time_master装饰器时便执行了相关语句,而在单独执行myfunc()函数时则会报错,具体情形请见截图.


我的困惑是如果在定义time_master函数时只有一层函数体的话,为何会出现这样的情况,请大神们赐教,谢谢!
屏幕截图 decor.png
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2025-2-8 20:58:59 | 显示全部楼层
好的,我来帮你解答这个问题。

当你定义一个装饰器时,通常会在装饰器内部定义一个嵌套函数,这样可以确保装饰器在执行时正确地处理被装饰的函数。

例如你的代码如下:
def time_master(func):
    def call_func():
       print('开始记录时间')
       start = time.time()
       func()
       end = time.time()
       print('时间记录终止')
       print(f'一共耗时:{(end - start)}')
    return call_func

@time_master
def myfunc():
    time.sleep(5)

myfunc()

在这种情况下,当 `myfunc` 被调用时,其实是调用了 `call_func`,而不是直接调用 `myfunc` 本身。这是因为装饰器 `@time_master` 修改了 `myfunc` 的行为,使之等同于 `call_func` 函数。

如果你没有定义嵌套的 `call_func` 函数,只保留一层函数体,那 `time_master` 函数会立即执行并返回它的内容。例如:
def time_master(func):
    print('开始记录时间')
    start = time.time()
    func()
    end = time.time()
    print('时间记录终止')
    print(f'一共耗时:{(end - start)}')
    return func

@time_master
def myfunc():
    time.sleep(5)

在这种情况下,`myfunc` 在定义时就会执行 `time_master` 函数,从而直接运行了 `myfunc`,并且返回了 `func`,这时 `myfunc` 并没有被正确装饰。当你之后再调用 `myfunc()` 时,它已经不是经过装饰器处理的版本,而是原始的 `myfunc` 函数,不能正确记录和打印时间。

正因为如此,你需要使用嵌套函数来确保装饰器正确封装被装饰的函数。

如果你有更多问题或需要进一步详细,说出来我继续帮你解答。

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

使用道具 举报

发表于 2025-2-9 09:30:49 | 显示全部楼层
本帖最后由 smallwh 于 2025-2-9 09:32 编辑
@time_master
def myfunc():
    time.sleep(5)
这样是一种简化的写法。函数装饰器完整的写法如下:
def myfunc():
    time.sleep(5)
myfunc = time_master(myfunc)
这种简化的方法称为语法糖,简化前后程序是等效的。
根据完整的代码,使用装饰器时,time_master 必须返回一个函数对象;且 myfunc 将不再是原来定义的 myfunc 函数,变成了 time_master 返回的那个函数对象。
你的代码中 time_master 返回了 None ,所以会报错。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

本版积分规则

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

GMT+8, 2025-2-24 01:33

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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