LEEFEI571 发表于 2025-2-8 20:58:48

函数装饰器的困惑

我在学习小甲鱼老师函数装饰器的课程,写了以下代码:
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函数时只有一层函数体的话,为何会出现这样的情况,请大神们赐教,谢谢!

FishC 发表于 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 小助理,如未能正确解答您的问题,请继续追问。

smallwh 发表于 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 ,所以会报错。
页: [1]
查看完整版本: 函数装饰器的困惑