Python で dict を使用したいのですが、キーと値のペアの数を X に制限します。つまり、dict が現在 X のキーと値のペアを格納していて、挿入を実行する場合、次のいずれかが必要です。ドロップする既存のペア。それが最も最近挿入された/アクセスされていないキーであればいいのですが、それは完全に必要というわけではありません。
これが標準ライブラリに存在する場合は、時間を節約して指摘してください!
Python で dict を使用したいのですが、キーと値のペアの数を X に制限します。つまり、dict が現在 X のキーと値のペアを格納していて、挿入を実行する場合、次のいずれかが必要です。ドロップする既存のペア。それが最も最近挿入された/アクセスされていないキーであればいいのですが、それは完全に必要というわけではありません。
これが標準ライブラリに存在する場合は、時間を節約して指摘してください!
Python 2.7および3.1にはOrderedDictがあり、以前のPython用の純粋なPython実装があります。
from collections import OrderedDict
class LimitedSizeDict(OrderedDict):
def __init__(self, *args, **kwds):
self.size_limit = kwds.pop("size_limit", None)
OrderedDict.__init__(self, *args, **kwds)
self._check_size_limit()
def __setitem__(self, key, value):
OrderedDict.__setitem__(self, key, value)
self._check_size_limit()
def _check_size_limit(self):
if self.size_limit is not None:
while len(self) > self.size_limit:
self.popitem(last=False)
また、など、アイテムを挿入できる他のメソッドをオーバーライドする必要がありますupdate
。の主な用途はOrderedDict
、ポップされるものを簡単に制御できるようにすることです。そうしないと、通常dict
は機能します。
Here is a simple and efficient LRU cache written with dirt simple Python code that runs on any python version 1.5.2 or later:
class LRU_Cache:
def __init__(self, original_function, maxsize=1000):
self.original_function = original_function
self.maxsize = maxsize
self.mapping = {}
PREV, NEXT, KEY, VALUE = 0, 1, 2, 3 # link fields
self.head = [None, None, None, None] # oldest
self.tail = [self.head, None, None, None] # newest
self.head[NEXT] = self.tail
def __call__(self, *key):
PREV, NEXT = 0, 1
mapping, head, tail = self.mapping, self.head, self.tail
link = mapping.get(key, head)
if link is head:
value = self.original_function(*key)
if len(mapping) >= self.maxsize:
old_prev, old_next, old_key, old_value = head[NEXT]
head[NEXT] = old_next
old_next[PREV] = head
del mapping[old_key]
last = tail[PREV]
link = [last, tail, key, value]
mapping[key] = last[NEXT] = tail[PREV] = link
else:
link_prev, link_next, key, value = link
link_prev[NEXT] = link_next
link_next[PREV] = link_prev
last = tail[PREV]
last[NEXT] = tail[PREV] = link
link[PREV] = last
link[NEXT] = tail
return value
if __name__ == '__main__':
p = LRU_Cache(pow, maxsize=3)
for i in [1,2,3,4,5,3,1,5,1,1]:
print(i, p(i, 2))
dictをサブクラス化することにより、カスタム辞書クラスを作成できます。あなたの場合、あなたは__setitem__
自分の長さをチェックするためにオーバーライドし、制限が回復した場合は何かを削除する必要があります。次の例では、挿入するたびに現在の長さを出力します。
class mydict(dict):
def __setitem__(self, k, v):
dict.__setitem__(self, k, v)
print len(self)
d = mydict()
d['foo'] = 'bar'
d['bar'] = 'baz'
dictにはこの動作はありません。これを行う独自のクラスを作成できます。たとえば、次のようになります。
class MaxSizeDict(object):
def __init__(self, max_size):
self.max_size = max_size
self.dict = {}
def __setitem__(self, key, value):
if key in self.dict:
self.dict[key] = value
return
if len(self.dict) >= self.max_size:
...
これについてのいくつかのメモ
dict
です。技術的にはこれを行うことができますが、メソッドが相互に依存しないため、バグが発生しやすくなります。UserDict.DictMixin
すべてのメソッドを定義する必要をなくすために使用できます。サブクラス化した場合に再利用できるメソッドはほとんどありませんdict
。collections.OrderedDict
ますが、今のところ、キーを個別に並べておくと正常に機能するはずです(collections.deque
キューとしてaを使用してください)。popitem
メソッドを使用して任意の1つのアイテムを削除できます。