我正在python中实现缓存服务。到目前为止,我正在使用一个简单的字典。我想做的是计算点击次数(按键检索存储值的次数)。Python builtin dict 没有这种可能性(据我所知)。我搜索了“python字典计数”并找到Counter
了(也在stackoverflow上),但这不满足我的要求。我不需要计算已经存在的东西。我需要增加一些来自外部的东西。而且我认为存储另一个只包含命中计数的字典并不是我能得到的最好的数据结构:)
你有什么想法如何有效地做到这一点?
我正在python中实现缓存服务。到目前为止,我正在使用一个简单的字典。我想做的是计算点击次数(按键检索存储值的次数)。Python builtin dict 没有这种可能性(据我所知)。我搜索了“python字典计数”并找到Counter
了(也在stackoverflow上),但这不满足我的要求。我不需要计算已经存在的东西。我需要增加一些来自外部的东西。而且我认为存储另一个只包含命中计数的字典并不是我能得到的最好的数据结构:)
你有什么想法如何有效地做到这一点?
对于另一种方法,如果您使用的是 Python 3(或者愿意将此模块添加到您的 Python 2 项目中,其界面略有不同),我强烈推荐使用lru_cache
装饰器。
请参阅此处的文档。例如,这段代码:
from functools import lru_cache
@lru_cache(maxsize=32)
def meth(a, b):
print("Taking some time", a, b)
return a + b
print(meth(2, 3))
print(meth(2, 4))
print(meth(2, 3))
...将输出:
Taking some time 2 3
5
Taking some time 2 4
6
5 <--- Notice that this function result is cached
根据文档,您可以使用 获取命中和未命中数meth.cache_info()
,并使用 清除缓存meth.cache_clear()
。
您可以子类化一个内置dict
类:
class CustomDict(dict):
def __init__(self, *args, **kwargs):
self.hits = {}
super(CustomDict, self).__init__(*args, **kwargs)
def __getitem__(self, key):
if key not in self.hits:
self.hits[key] = 0
self.hits[key] += 1
return super(CustomDict, self).__getitem__(key)
用法:
>>> d = CustomDict()
>>> d["test"] = "test"
>>> d["test"]
'test'
>>> d["test"]
'test'
>>> d.hits["test"]
2
拥有另一个字典来存储命中计数可能不是一个坏选择,但您也可以执行以下操作:
class CacheService(object):
def __init__(self):
self.data = {}
def __setitem__(self, key, item):
self.data[key] = [item, 0]
def __getitem__(self, key):
value = self.data[key]
value[1] += 1
return value[0]
def getcount(self, key):
return self.data[key][1]
你可以像这样使用它:
>>> cs = CacheService()
>>> cs[1] = 'one'
>>> cs[2] = 'two'
>>> print cs.getcount(1)
0
>>> cs[1]
'one'
>>> print cs.getcount(1)
1
重载内置的 dict 数据类型会容易得多。这将解决您的问题。
def CountDict(dict):
count = {}
def __getitem__(self, key):
CountDict.count[key] = CountDict.count.get(key, 0) + 1
return super(CountDict, self).__getitem__(self, key)
def __setitem__(self, key, value):
return super(CountDict, self).__setitem__(self, key, value)
def get_count(self, key):
return CountDict.count.get(key, 0)
这会给你更多的灵活性。就像您可以有两个计数,一个用于读取次数,另一个用于写入次数,如果您希望没有太多复杂性的话。要了解有关 super 的更多信息,请参见此处。
编辑以满足 OP 保持计数以读取密钥的需要。可以通过调用 get_count 方法获得输出。
>>>my_dict = CountDict()
>>>my_dict["a"] = 1
>>>my_dict["a"]
>>>1
>>>my_dict["a"]
>>>1
>>>my_dict.get_count("a")
>>>2
免责声明:我是kids.cache
您可能需要检查kids.cache,这是一个默认用作缓存存储的简单库,dict
并将返回包括命中和未命中在内的缓存统计信息。
>>> from kids.cache import cache
>>> @cache
... def meth(a, b):
... print("Taking some time", a, b)
... return a + b
一次失误和一次成功:
>>> meth(1, 2) ## Miss !
Taking some time 1 2
3
>>> meth(1, 2) ## Hit !
3
让我们添加一个错过:
>>> meth(1, 3) ## Miss !
Taking some time 1 2
4
现在让我们询问缓存信息:
>>> meth.cache_info()
CacheInfo(type='dict', hits=1, misses=2, maxsize=None, currsize=2)
您可以查看kids.cache 的源代码,了解缓存信息是如何实现的。请注意,它不会将统计信息存储在缓存存储中。保存值的是缓存函数。
我相信这是最干净的方式,因为它允许您使用各种缓存存储(有些像旧的一样简单dict
),而无需在每个缓存中实现缓存统计功能。最后一个想法来自 Thomas Kemmer ,他编写了出色的缓存工具。
您可能还可以使用kids.cache
具有大量文档的开箱即用。它没有依赖关系,只有一个文件,适用于 python2 和 python3,使用简单,同时在必要时还允许进行复杂的缓存。