松V溪 发表于 2023-7-28 16:50:13

闭包与装饰器函数类型为Nonetype

import time

def time_master(msg):
    def call_func(func):
      print("开始运行程序...")
      start = time.time()
      func()
      stop = time.time()
      print("结束程序运行...")
      print(f"[{msg}]一共耗费了{(stop - start):.2f}秒。")
      return
    return call_func


@time_master('你好')
def myfunc():
    time.sleep(2)
    print("I Love FichC ^o^")

print(myfunc.__name__)请问一下,为什么现在的myfunc类型是一个nonetype啊

陶远航 发表于 2023-7-28 16:50:31

在这个示例中,您使用了装饰器函数@time_master('你好')来装饰myfunc()函数。装饰器函数的作用是在不修改被装饰函数源代码的情况下,为其添加额外的功能。

在您的代码中,time_master()函数返回了内部定义的函数call_func(),并且call_func()函数被装饰器应用到myfunc()上。当装饰器应用后,原本的myfunc()函数已经被call_func()函数替代了,因此调用myfunc()实际上会执行call_func()函数的逻辑。

由于call_func()函数没有明确的返回值,它的返回类型默认为NoneType,所以经过装饰后的myfunc()函数也会返回NoneType。

如果您希望保留myfunc()的原始类型,可以在call_func()函数中添加一个return func语句,将原始函数返回。这样,myfunc()函数的类型将与原始函数类型相同。例如:

def time_master(msg):
    def call_func(func):
      print("开始运行程序...")
      start = time.time()
      func()
      stop = time.time()
      print("结束程序运行...")
      print(f"[{msg}]一共耗费了{(stop - start):.2f}秒。")
      return func# 添加此行

    return call_func

@time_master('你好')
def myfunc():
    time.sleep(2)
    print("I Love FichC ^o^")

print(myfunc.__name__)# 输出:myfunc


通过添加return func语句,您可以保留原始函数的类型。
如果问题已经解决,请设置最佳答案

isdkz 发表于 2023-7-28 16:50:34

在这个代码中,出现 myfunc 类型为 NoneType 的问题是因为装饰器函数 time_master 没有正确返回内部函数 call_func 的引用。

让我们来分析代码的执行过程:

1. 定义了 time_master 装饰器函数,它接受一个 msg 参数,并返回一个内部函数 call_func 。
2. 在定义 myfunc 函数之前,使用 @time_master('你好') 语法将 myfunc 函数装饰了起来。这相当于执行了 myfunc = time_master('你好')(myfunc) ,即用 time_master('你好') 返回的函数对象来重新绑定 myfunc 变量。
3.call_func 内部函数在被调用时会执行传入的函数 func() ,在这里就是 myfunc() 。
4.myfunc 函数内部执行了 time.sleep(2) 来模拟耗时操作,然后打印一条消息。

然而, call_func 内部没有返回任何值,而是直接使用了 func() 执行了 myfunc() 函数。因为 myfunc 函数本身没有返回值,所以 call_func 内部的 return 语句实际上返回了默认值 None ,导致 myfunc 函数被装饰后,其类型变为 NoneType 。

为了解决这个问题,你需要在 call_func 内部添加一个返回语句,将 func() 的返回值传递给外部调用。修改代码如下:

import time

def time_master(msg):
    def call_func(func):
      print("开始运行程序...")
      start = time.time()
      result = func()# 调用func,并获取其返回值
      stop = time.time()
      print("结束程序运行...")
      print(f"[{msg}]一共耗费了{(stop - start):.2f}秒。")
      return result# 返回func的返回值
    return call_func


@time_master('你好')
def myfunc():
    time.sleep(2)
    print("I Love FichC ^o^")

print(myfunc.__name__)


现在, myfunc 应该会被正确地装饰,并且其类型不再是 NoneType ,而是一个函数类型。

歌者文明清理员 发表于 2023-7-28 16:53:45

报错了呀
开始运行程序...
I Love FichC ^o^
结束程序运行...
[你好]一共耗费了2.01秒。
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
Cell In, line 20
   17   time.sleep(2)
   18   print("I Love FichC ^o^")
---> 20 print(myfunc.__name__)

AttributeError: 'NoneType' object has no attribute '__name__'

松V溪 发表于 2023-7-29 14:24:32

歌者文明清理员 发表于 2023-7-28 16:53
报错了呀

对啊,因为这个时候的myfunc类型是一个NoneType类型,所以它会报错,但是现在我知道问题在哪里了{:10_256:}

松V溪 发表于 2023-7-29 14:27:34

isdkz 发表于 2023-7-28 16:50
在这个代码中,出现 myfunc 类型为 NoneType 的问题是因为装饰器函数 time_master 没有正确返回内部函数 ca ...

厉害,return restult中restult是什么啊?python内置的吗?我昨天想的是直接return func.

isdkz 发表于 2023-7-29 14:29:36

松V溪 发表于 2023-7-29 14:27
厉害,return restult中restult是什么啊?python内置的吗?我昨天想的是直接return func.

result 就是 func 调用的返回值呀,我把 func() 赋值给 result 了

歌者文明清理员 发表于 2023-7-29 14:30:53

松V溪 发表于 2023-7-29 14:24
对啊,因为这个时候的myfunc类型是一个NoneType类型,所以它会报错,但是现在我知道问题在哪里了{:10_256 ...

这个表情……{:10_256:}{:10_256:}{:10_256:}{:10_256:}{:10_256:}{:10_256:}{:10_256:}{:10_256:}{:10_256:}{:10_256:}{:10_256:}{:10_256:}

松V溪 发表于 2023-7-29 14:32:13

isdkz 发表于 2023-7-29 14:29
result 就是 func 调用的返回值呀,我把 func() 赋值给 result 了

okk,感谢,我当时没看前面{:10_266:}
页: [1]
查看完整版本: 闭包与装饰器函数类型为Nonetype