鱼C论坛

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

[已解决]使用装饰器计算递归函数运行时间的一个问题

[复制链接]
发表于 2023-6-26 19:27:17 | 显示全部楼层 |阅读模式

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

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

x
问题来源:python最新版中的递归课后作业中,要求分别计算普通递归、尾递归和迭代方式相应的解决时间。本人尝试使用之前使用的装饰器知识去解决,代码如下:
import time
def timee(func): #装饰器函数,用于计算函数运行时间
    def inner(n):
        t1 = time.time()
        func(n)
        t2 = time.time()
        print(f"耗时:{t2-t1}")
    return inner

@timee
def fibRecur(n): #待计算运行时间的斐波拉契函数(普通递归算法实现)
     if n == 1 or n == 2:
         return 1
     else:
         return fibRecur(n-1) + fibRecur(n-2)
fibRecur(12) #12为计算斐波拉契数列第12项的结果

运行结果:
耗时:0.0
耗时:0.0
[color=Red]Traceback (most recent call last):
  File "F:\Programs\Python\HomeWork\fibtime.py", line 16, in <module>
    fibRecur(12)
  File "F:\Programs\Python\HomeWork\fibtime.py", line 5, in inner
    func(n)
  File "F:\Programs\Python\HomeWork\fibtime.py", line 15, in fibRecur
    return fibRecur(n-1) + fibRecur(n-2)
  File "F:\Programs\Python\HomeWork\fibtime.py", line 5, in inner
    func(n)
  File "F:\Programs\Python\HomeWork\fibtime.py", line 15, in fibRecur
    return fibRecur(n-1) + fibRecur(n-2)
  File "F:\Programs\Python\HomeWork\fibtime.py", line 5, in inner
    func(n)
  File "F:\Programs\Python\HomeWork\fibtime.py", line 15, in fibRecur
    return fibRecur(n-1) + fibRecur(n-2)
  File "F:\Programs\Python\HomeWork\fibtime.py", line 5, in inner
    func(n)
  File "F:\Programs\Python\HomeWork\fibtime.py", line 15, in fibRecur
    return fibRecur(n-1) + fibRecur(n-2)
  File "F:\Programs\Python\HomeWork\fibtime.py", line 5, in inner
    func(n)
  File "F:\Programs\Python\HomeWork\fibtime.py", line 15, in fibRecur
    return fibRecur(n-1) + fibRecur(n-2)
  File "F:\Programs\Python\HomeWork\fibtime.py", line 5, in inner
    func(n)
  File "F:\Programs\Python\HomeWork\fibtime.py", line 15, in fibRecur
    return fibRecur(n-1) + fibRecur(n-2)
  File "F:\Programs\Python\HomeWork\fibtime.py", line 5, in inner
    func(n)
  File "F:\Programs\Python\HomeWork\fibtime.py", line 15, in fibRecur
    return fibRecur(n-1) + fibRecur(n-2)
  File "F:\Programs\Python\HomeWork\fibtime.py", line 5, in inner
    func(n)
  File "F:\Programs\Python\HomeWork\fibtime.py", line 15, in fibRecur
    return fibRecur(n-1) + fibRecur(n-2)
  File "F:\Programs\Python\HomeWork\fibtime.py", line 5, in inner
    func(n)
  File "F:\Programs\Python\HomeWork\fibtime.py", line 15, in fibRecur
    return fibRecur(n-1) + fibRecur(n-2)
  File "F:\Programs\Python\HomeWork\fibtime.py", line 5, in inner
    func(n)
  File "F:\Programs\Python\HomeWork\fibtime.py", line 15, in fibRecur
    return fibRecur(n-1) + fibRecur(n-2)
TypeError: unsupported operand type(s) for +: 'NoneType' and 'NoneType'

想请问出现上述异常的原因是什么?如何改进代码?
最佳答案
2023-6-26 19:35:24
你的代码中出现这个错误是因为你在装饰器函数中没有返回 func(n) 的结果。你的装饰器函数只是计算了运行时间,然后打印了这个时间,但并没有返回原函数的计算结果。在斐波那契数列的计算过程中,你需要将每一步的结果返回给上一步以便计算,所以在这里你需要返回 func(n) 的结果。

你可以将你的装饰器函数修改如下:
import time

def timee(func): #装饰器函数,用于计算函数运行时间
    def inner(n):
        t1 = time.time()
        result = func(n) # 收集函数结果
        t2 = time.time()
        print(f"耗时:{t2-t1}")
        return result # 返回函数结果
    return inner

@timee
def fibRecur(n): #待计算运行时间的斐波拉契函数(普通递归算法实现)
     if n == 1 or n == 2:
         return 1
     else:
         return fibRecur(n-1) + fibRecur(n-2)

这样修改后,你的装饰器函数除了计算运行时间之外,还会返回原函数的计算结果,这样在斐波那契数列的计算过程中就不会出现 'NoneType' 错误了。

但这样一来,你的装饰器会对每一次递归都进行计时,而我们通常需要的是整个函数从开始到结束的运行时间,而不是每一次递归的运行时间。所以在实际使用中,可能需要进一步优化你的装饰器以实现对整个函数运行时间的计算。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2023-6-26 19:35:24 | 显示全部楼层    本楼为最佳答案   
你的代码中出现这个错误是因为你在装饰器函数中没有返回 func(n) 的结果。你的装饰器函数只是计算了运行时间,然后打印了这个时间,但并没有返回原函数的计算结果。在斐波那契数列的计算过程中,你需要将每一步的结果返回给上一步以便计算,所以在这里你需要返回 func(n) 的结果。

你可以将你的装饰器函数修改如下:
import time

def timee(func): #装饰器函数,用于计算函数运行时间
    def inner(n):
        t1 = time.time()
        result = func(n) # 收集函数结果
        t2 = time.time()
        print(f"耗时:{t2-t1}")
        return result # 返回函数结果
    return inner

@timee
def fibRecur(n): #待计算运行时间的斐波拉契函数(普通递归算法实现)
     if n == 1 or n == 2:
         return 1
     else:
         return fibRecur(n-1) + fibRecur(n-2)

这样修改后,你的装饰器函数除了计算运行时间之外,还会返回原函数的计算结果,这样在斐波那契数列的计算过程中就不会出现 'NoneType' 错误了。

但这样一来,你的装饰器会对每一次递归都进行计时,而我们通常需要的是整个函数从开始到结束的运行时间,而不是每一次递归的运行时间。所以在实际使用中,可能需要进一步优化你的装饰器以实现对整个函数运行时间的计算。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-6-26 19:37:03 | 显示全部楼层
本帖最后由 sfqxx 于 2023-6-26 19:39 编辑

出现上述异常的原因是在装饰器函数 inner 中,你没有正确传递返回值。这导致了斐波那契递归函数的递归调用返回了 None,无法进行加法操作。

要改进代码,你需要在递归函数 fibRecur() 中使用 return 语句返回计算结果,以确保每个递归调用都返回相应的值。同时,在装饰器函数 inner 中,你需要将递归函数的返回值返回给调用者。

以下是改进后的代码示例:

import time

def timee(func): 
    def inner(n):
        t1 = time.time()
        result = func(n)
        t2 = time.time()
        print(f"耗时:{t2-t1}")
        return result
    return inner

@timee
def fibRecur(n): 
    if n == 1 or n == 2:
        return 1
    else:
        return fibRecur(n-1) + fibRecur(n-2)

fibRecur(12)
改进后的代码会正确计算斐波那契递归函数的运行时间,并给出正确的结果。

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

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-12-26 21:27

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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