我想看看两种计算斐波那契数列的方法之间的时间成本差异: 首先,我创建了一个装饰器,将“输出时间成本”函数添加到一个函数中:
def time_cost(func):
def wed(n):
start = time.time()
func(n)
stop = time.time()
print(stop-start)
return wed
然后我写了第一个函数:
@time_cost
def DP_F(n):
f = [1,1]
while len(f)<n:
f.append(f[len(f)-1]+f[len(f)-2])
return f
效果很好
>>> DP_F(10)
0.0
>>> DP_F(100)
0.0
>>> DP_F(10000)
0.007944107055664062
但是当我用装饰器创建第二个函数时发生了错误:
@time_cost
def R_F(n):
if n<=2:
return 1
else:
return R_F(n-1)+R_F(n-2)
引发错误,提示某些输出可能会丢失
>>> R_F(10)
0.0
0.0
Traceback (most recent call last):
File "<pyshell#44>", line 1, in <module>
R_F(10)
File "<pyshell#28>", line 4, in wed
func(n)
File "<pyshell#43>", line 8, in R_F
return R_F(n-1)+R_F(n-2)
File "<pyshell#28>", line 4, in wed
func(n)
File "<pyshell#43>", line 8, in R_F
return R_F(n-1)+R_F(n-2)
File "<pyshell#28>", line 4, in wed
func(n)
File "<pyshell#43>", line 8, in R_F
return R_F(n-1)+R_F(n-2)
File "<pyshell#28>", line 4, in wed
func(n)
File "<pyshell#43>", line 8, in R_F
return R_F(n-1)+R_F(n-2)
File "<pyshell#28>", line 4, in wed
func(n)
File "<pyshell#43>", line 8, in R_F
return R_F(n-1)+R_F(n-2)
File "<pyshell#28>", line 4, in wed
func(n)
File "<pyshell#43>", line 8, in R_F
return R_F(n-1)+R_F(n-2)
File "<pyshell#28>", line 4, in wed
func(n)
File "<pyshell#43>", line 8, in R_F
return R_F(n-1)+R_F(n-2)
File "<pyshell#28>", line 4, in wed
func(n)
File "<pyshell#43>", line 8, in R_F
return R_F(n-1)+R_F(n-2)
TypeError: unsupported operand type(s) for +: 'NoneType' and 'NoneType'
因此Python装饰器无法装饰递归函数吗?
答案 0 :(得分:2)
当前的问题是wed
不返回func
的返回值。很容易解决。
def time_cost(func): def wed(n): start = time.time() n = func(n) stop = time.time() print(stop-start) return n return wed
但是,现在看一下致电R_F(3)
时会发生什么。
>>> R_F(3)
9.5367431640625e-07
1.1920928955078125e-06
0.0001671314239501953
2
您获得 3 次:每个递归调用一次。这是因为原始函数调用了绑定到的任何R_F
,现在是函数wed
,而不是实际的斐波那契函数。
使用上下文管理器可以更好地处理这种情况。
from contextlib import contextmanager
@contextmanager
def time_cost():
start = time.time()
yield
stop = time.time()
print(stop - start)
with time_cost():
R_F(3)
从某种意义上说,Python没有递归函数。一个函数不能调用自身,而只有绑定到您期望的名称的某个函数会引用您的函数。称之为“合作递归”。
例如,考虑递归函数的标准示例,阶乘。
def fact(x):
return 1 if x == 0 else x * fact(x-1)
我们可以通过重新绑定名称fact
来轻松解决这个问题。
g = fact # save a reference to the original function
def fact(x):
print("Broken")
return 0
现在g(3)
打印Broken
并返回0,因为它将尝试调用绑定到 now 的任何fact
,而不是调用fact
在您重新定义它之前就已经绑定了。
如果要使用“安全”递归函数,则必须使用私有递归帮助器对其进行定义。
def fact(x):
def helper(x):
return 1 if x == 0 else x * helper(x - 1)
return helper(x)
现在您可以安全地装饰fact
,因为无论绑定到fact
(无论是原始功能还是装饰功能),helper
都不会反弹。