словарь кеша python – подсчет количества обращений

Я выполняю кэширование в python. До сих пор я использую простой словарь. То, что я хотел бы сделать, – подсчитать количество обращений (количество раз, когда хранимое значение было извлечено ключом). У Python builtin dict нет такой возможности (насколько я знаю). Я искал «счетчик слов python» и нашел Counter (также в stackoverflow), но это не удовлетворяет моим требованиям, я думаю. Мне не нужно считать, что уже существует. Мне нужно увеличивать то, что приходит извне. И я думаю, что сохранение другого словаря с подсчетами хитов – это не лучшая структура данных, которую я могу получить 🙂

У вас есть идеи, как это сделать эффективно?

Наличие другого словаря для хранения счетчиков попаданий, вероятно, не является плохим вариантом, но вы также можете сделать что-то вроде:

 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 :

 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 

Для альтернативного метода, если вы используете 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. Это решит вашу проблему.

 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) 

Это даст вам большую гибкость. Как и у вас может быть два счета: один для числа чтений, а другой – для количества записей, если вы хотите без большой сложности. Чтобы узнать больше о супер, см. Здесь .

Отредактировано, чтобы удовлетворить потребность ФП в хранении счета для чтения ключа. Вывод можно получить, вызвав метод 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

Возможно, вы захотите проверить child.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) 

Пойти дальше

Вы можете проверить исходный код child.cache, чтобы узнать, как реализована информация кэширования. Обратите внимание, что он НЕ хранит статистику внутри хранилища кеша. Это функция кеша, которая содержит значение.

Я считаю, что это самый чистый способ, поскольку он позволяет использовать широкие вариации хранилищ кеш-памяти (а некоторые такие же простые, как старый добрый dict ), без необходимости выполнять функцию кеширования в каждой из них. Эта последняя идея исходит от Томаса Кеммера, который написал превосходные кешью .

Возможно, вы также можете использовать из коробки kids.cache который имеет обширные документы . Он не имеет никакой зависимости, только один файл, работающий на python2 и python3, прост в использовании, позволяя при необходимости также сложное кэширование.