鱼C论坛

 找回密码
 立即注册
查看: 1555|回复: 8

[已解决]闭包与装饰器函数类型为Nonetype

[复制链接]
发表于 2023-7-28 16:50:13 | 显示全部楼层 |阅读模式

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

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

x
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: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 ,而是一个函数类型。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 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语句,您可以保留原始函数的类型。
如果问题已经解决,请设置最佳答案
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 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 ,而是一个函数类型。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-7-28 16:53:45 | 显示全部楼层
报错了呀
开始运行程序...
I Love FichC ^o^
结束程序运行...
[你好]一共耗费了2.01秒。
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
Cell In[1], line 20
     17     time.sleep(2)
     18     print("I Love FichC ^o^")
---> 20 print(myfunc.__name__)

AttributeError: 'NoneType' object has no attribute '__name__'
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 1 反对 0

使用道具 举报

 楼主| 发表于 2023-7-29 14:24:32 | 显示全部楼层

对啊,因为这个时候的myfunc类型是一个NoneType类型,所以它会报错,但是现在我知道问题在哪里了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

厉害,return restult中restult是什么啊?python内置的吗?我昨天想的是直接return func.
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

result 就是 func 调用的返回值呀,我把 func() 赋值给 result 了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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


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

使用道具 举报

 楼主| 发表于 2023-7-29 14:32:13 | 显示全部楼层
isdkz 发表于 2023-7-29 14:29
result 就是 func 调用的返回值呀,我把 func() 赋值给 result 了

okk,感谢,我当时没看前面
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-9-22 07:32

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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