如何让Python记住在函数中创建的列表以供将来使用
下面是一个迭代计算如何让Python记住在函数中创建的列表以供将来使用,python,scope,fibonacci,memoization,Python,Scope,Fibonacci,Memoization,下面是一个迭代计算 def fibonacci(n): 如果n
def fibonacci(n):
如果n<0:
raise VALUERROR(“无效索引!”)
如果n==0:
返回0
如果n==1:
返回1
f=[0,1]
对于范围(2,n+1)内的i:
f、 附加(f[i-1]+f[i-2])
返回f[n]
实际上,listf
是函数内部的局部变量,每次调用fibonacci
函数时都会重新创建和重新填充。
如何重写此代码段,以便Python在调用
fibonacci(5)
后不需要重新计算它,并且可以在下次调用fibonacci(5)
或更高版本时使用它?我知道全局变量是一个选项,但最“python”的方法是什么?您可以使用闭包来记忆结果:在这种情况下,在首次执行函数时(通常是在加载模块时)创建memo dict;它是持久的,在调用函数时填充
def fibonacci(n, memo={}):
try:
return memo[n]
except KeyError:
pass
if n < 0:
raise ValueError("fibonacci must be called with positive numbers")
if n == 0:
memo[n] = 0
return 0
if n == 1:
memo[n] = 1
return 1
memo[n] = fibonacci(n-1) + fibonacci(n-2)
return memo[n]
def fibonacci(n,memo={}):
尝试:
返回备忘录[n]
除KeyError外:
通过
如果n<0:
raise VALUERROR(“必须用正数调用斐波那契”)
如果n==0:
备注[n]=0
返回0
如果n==1:
备忘录[n]=1
返回1
备忘录[n]=斐波那契(n-1)+斐波那契(n-2)
返回备忘录[n]
您可以将f
存储在函数范围之外的变量中。例如:
def memoize_fibonacci():
f = [0,1]
def inner_fibonacci(n):
if n < 0:
raise ValueError("invalid index!")
for i in range(len(f),n+1):
f.append(f[i-1] + f[i-2])
return f[n]
return inner_fibonacci
如果我们现在两次查询第20万个元素,第二次查询速度更快。使用python字典,检查键是否存在,并从字典返回结果,或者在返回之前计算结果并将其添加到字典中
fib_dict = {};
def fibonacci(n):
if n in fib_dict:
return fib_dict[n];
else:
if n < 0:
raise ValueError("invalid index!")
if n==0:
return 0
if n==1:
return 1
f = [0,1]
for i in range(2,n+1):
f.append(f[i-1] + f[i-2])
fib_dict[n] = f[n];
return f[n];
fib_dict={};
def fibonacci(n):
如果fib_dict中的n:
返回fib_dict[n];
其他:
如果n<0:
raise VALUERROR(“无效索引!”)
如果n==0:
返回0
如果n==1:
返回1
f=[0,1]
对于范围(2,n+1)内的i:
f、 附加(f[i-1]+f[i-2])
fib_dict[n]=f[n];
返回f[n];
global
或将可变变量传递给函数。您可能希望检查更好的实现的备选方案:您应该查找Memorization。举个例子:这有关系吗?我不明白这整件pythonic
宗教的废话。如果它解决了您的问题,并且是一个可读的或快速的操作,那不是很好吗?无论如何,是的,它是pythonic-.-@Torxed全局变量既不是快速的、线程安全的,也不是pythonic的(这仅仅意味着以最直接和前瞻性的方式使用该语言,而不是像您习惯于使用另一种语言那样)。有很多人喜欢将代码黑客化,而不考虑可维护性或可靠性,所以无论如何都可以随意这么做;-)memo dict是在执行函数定义时创建的(通常是在导入它所驻留的文件时),而不是在第一次调用函数时创建的。由于其递归性质,这会导致初始调用fibonacci(1000)
,其他解决方案可以处理该调用。备忘录对此没有帮助。另外,从技术上来说,这是一个终结吗?即,谁的变量是memo
?(除了增加Python的堆栈大小外,您还可以通过调用fibonacci(900)
beforefibonacci(1000)
来轻松解答这个问题!)这实际上比使用Binet公式要快,也有相当大的差距(!)谢谢,@Willem Van Onsem,如果没有最后一行fibonacci=memoize\u fibonacci
而只是使用memoize\u fibonacci
作为函数,会有什么不同吗?就运行时间而言?@Semihcan:是的。因为memoize\u fibonacci
不是fibonacci函数。它是斐波那契函数的工厂。
fibonacci = memoize_fibonacci()
fib_dict = {};
def fibonacci(n):
if n in fib_dict:
return fib_dict[n];
else:
if n < 0:
raise ValueError("invalid index!")
if n==0:
return 0
if n==1:
return 1
f = [0,1]
for i in range(2,n+1):
f.append(f[i-1] + f[i-2])
fib_dict[n] = f[n];
return f[n];