Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/276.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/python-3.x/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python decorator可以修饰递归函数吗?_Python_Python 3.x_Recursion_Decorator - Fatal编程技术网

Python decorator可以修饰递归函数吗?

Python decorator可以修饰递归函数吗?,python,python-3.x,recursion,decorator,Python,Python 3.x,Recursion,Decorator,我想看看计算斐波那契序列的两种方法之间的时间成本差异: 首先,我创建了一个decorator,将“输出时间成本”函数添加到函数中: 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

我想看看计算斐波那契序列的两种方法之间的时间成本差异: 首先,我创建了一个decorator,将“输出时间成本”函数添加到函数中:

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
然后我编写了第一个函数:

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
但是当我用decorator创建第二个函数时,发生了一些错误:

@time_cost
def R_F(n):
    if n<=2:
        return 1
    else:
        return R_F(n-1)+R_F(n-2)
@时间成本
def R_F(n):
如果n>>R\u F(10)
0
0
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
R_F(10)
文件“”,第4行,星期三
func(n)
文件“”,第8行,在R\u F中
返回R_F(n-1)+R_F(n-2)
文件“”,第4行,星期三
func(n)
文件“”,第8行,在R\u F中
返回R_F(n-1)+R_F(n-2)
文件“”,第4行,星期三
func(n)
文件“”,第8行,在R\u F中
返回R_F(n-1)+R_F(n-2)
文件“”,第4行,星期三
func(n)
文件“”,第8行,在R\u F中
返回R_F(n-1)+R_F(n-2)
文件“”,第4行,星期三
func(n)
文件“”,第8行,在R\u F中
返回R_F(n-1)+R_F(n-2)
文件“”,第4行,星期三
func(n)
文件“”,第8行,在R\u F中
返回R_F(n-1)+R_F(n-2)
文件“”,第4行,星期三
func(n)
文件“”,第8行,在R\u F中
返回R_F(n-1)+R_F(n-2)
文件“”,第4行,星期三
func(n)
文件“”,第8行,在R\u F中
返回R_F(n-1)+R_F(n-2)
TypeError:+:“非类型”和“非类型”的操作数类型不受支持

所以Python装饰器不能装饰递归函数

直接的问题是
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 您将获得3次:每次递归调用一次。这是因为原始函数调用绑定到的任何
R\u 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)
打印
breaked
并返回0,因为它将尝试调用现在绑定到的
fact
,而不是重新定义它之前绑定到的
fact

如果你想要一个“安全”的递归函数,你必须用一个私有的递归助手来定义它

def fact(x):
    def helper(x):
        return 1 if x == 0 else x * helper(x - 1)
    return helper(x)

现在您可以安全地修饰
fact
,因为无论
fact
绑定到什么(无论是原始函数还是修饰函数),
helper
都不会反弹。

您的包装器在
wed
内部返回
None
,您调用了
func(n)
(在本例中,可以是
DP\u F
R\u F
中的任意一个)不捕获并返回该结果。默认返回值变为
None
,这解释了错误。这不是因为Python装饰程序无法装饰递归函数。可以,但重复调用的是装饰函数,而不是原始函数。每个“递归”调用将调用
wed
,它启动一个新的计时器并执行一个新的
print
语句。使用上下文管理器比使用装饰器更好地处理这种情况。
def fact(x):
    def helper(x):
        return 1 if x == 0 else x * helper(x - 1)
    return helper(x)