我刚开始学习Python,我不知道什么是内存化,也不知道如何使用它。另外,我可以举一个简单的例子吗?
当前回答
我发现这非常有用
from functools import wraps
def memoize(function):
memo = {}
@wraps(function)
def wrapper(*args):
# add the new key to dict if it doesn't exist already
if args not in memo:
memo[args] = function(*args)
return memo[args]
return wrapper
@memoize
def fibonacci(n):
if n < 2: return n
return fibonacci(n - 1) + fibonacci(n - 2)
fibonacci(25)
其他回答
如果要考虑速度:
@functools。cache和@functools.lru_cache(maxsize=None)同样快,在我的系统上循环一百万次需要0.122秒(最好运行15次) 全局缓存变量要慢得多,在我的系统上循环一百万次需要0.180秒(最好运行15次) 一个自我。缓存类变量仍然有点慢,在我的系统上循环一百万次需要0.214秒(最好运行15次)
后两者的实现方式与目前投票最多的答案中描述的类似。
这没有防止内存耗尽,也就是说,我没有在类或全局方法中添加代码来限制缓存的大小,这真的是最基本的实现。如果需要的话,lru_cache方法可以免费提供。
对我来说,一个悬而未决的问题是如何对具有functools装饰器的东西进行单元测试。是否有可能以某种方式清空缓存?单元测试似乎使用class方法(在这里您可以为每个测试实例化一个新类)或全局变量方法(因为您可以使用您的rimportedmodule)是最干净的。Cachevariable ={}来清空它)。
记忆是将函数转换为数据结构的过程。通常,人们希望增量地、惰性地进行转换(根据给定的域元素——或“键”的要求)。在惰性函数语言中,这种惰性转换可以自动发生,因此可以在没有(显式)副作用的情况下实现内存化。
functools。缓存装饰:
Python 3.9发布了一个新函数functools.cache。它在内存中缓存带有一组特定参数的函数调用的结果,这就是内存化。它很容易使用:
import functools
import time
@functools.cache
def calculate_double(num):
time.sleep(1) # sleep for 1 second to simulate a slow calculation
return num * 2
第一次调用caculate_double(5)时,它将花费一秒钟并返回10。第二次使用相同的参数calculate_double(5)调用该函数时,它将立即返回10。
添加缓存装饰器可以确保如果函数最近为某个特定值被调用,它将不会重新计算该值,而是使用先前缓存的结果。在这种情况下,它可以极大地提高速度,同时代码不会因为缓存的细节而变得混乱。
(编辑:前面的示例使用递归计算了斐波那契数,但我修改了示例以防止混淆,因此出现了旧的注释。)
functools。lru_cache装饰:
如果您需要支持旧版本的Python,请使用functools。lru_cache适用于Python 3.2+。默认情况下,它只缓存最近使用的128个调用,但你可以将maxsize设置为None来指示缓存永远不会过期:
@functools.lru_cache(maxsize=None)
def calculate_double(num):
# etc
记忆实际上是指根据方法输入记住(“记忆”→“备忘录”→被记住)方法调用的结果,然后返回记住的结果,而不是重新计算结果。您可以把它看作是方法结果的缓存。更多详细信息,请参阅第387页的算法介绍(3e), Cormen等人的定义。
在Python中使用内存计算阶乘的简单示例如下:
factorial_memo = {}
def factorial(k):
if k < 2: return 1
if k not in factorial_memo:
factorial_memo[k] = k * factorial(k-1)
return factorial_memo[k]
你可以做得更复杂一些,把记忆过程封装到一个类中:
class Memoize:
def __init__(self, f):
self.f = f
self.memo = {}
def __call__(self, *args):
if not args in self.memo:
self.memo[args] = self.f(*args)
#Warning: You may wish to do a deepcopy here if returning objects
return self.memo[args]
然后:
def factorial(k):
if k < 2: return 1
return k * factorial(k - 1)
factorial = Memoize(factorial)
Python 2.4中添加了一个被称为“装饰器”的特性,它允许你现在简单地编写以下代码来完成同样的事情:
@Memoize
def factorial(k):
if k < 2: return 1
return k * factorial(k - 1)
Python装饰器库有一个类似的装饰器,称为memoized,它比这里显示的Memoize类稍微健壮一些。
不要忘记内置的hasattr函数,对于那些想要手工制作的人来说。这样就可以将mem缓存保存在函数定义中(而不是全局缓存)。
def fact(n):
if not hasattr(fact, 'mem'):
fact.mem = {1: 1}
if not n in fact.mem:
fact.mem[n] = n * fact(n - 1)
return fact.mem[n]
推荐文章
- 使用python创建一个简单的XML文件
- APT命令行界面式的yes/no输入?
- 如何打印出状态栏和百分比?
- 在Python中获取大文件的MD5哈希值
- 在Python格式字符串中%s是什么意思?
- 如何循环通过所有但最后一项的列表?
- python用什么方法避免默认参数为空列表?
- ValueError: numpy。Ndarray大小改变,可能表示二进制不兼容。期望从C头得到88,从PyObject得到80
- Anaconda /conda -安装特定的软件包版本
- 我在哪里调用Keras的BatchNormalization函数?
- 打印测试执行时间并使用py.test锁定缓慢的测试
- 插入一行到熊猫数据框架
- 要列出Pandas DataFrame列
- 在Django模型中存储电话号码的最佳方法是什么?
- 从导入的模块中模拟函数